I need a quick way of converting a pair of integers to a byte array. If it were a single value, I could use the following:
private static unsafe byte[] ToBytes(int value)
{
var bytes = new byte[4];
fixed (byte* pointer = bytes)
{
*(int*)pointer = value;
}
return bytes;
}
However I can't quite figure out how you'd do the same for a pair of integers. The following which I tried doesn't work but should help to show what I'm aiming for
private static unsafe byte[] ToBytes(int value1, int value2)
{
var bytes = new byte[8];
fixed (byte* pointer = bytes)
{
*(int*)pointer = value1;
*(int*)pointer + 4 = value2;
}
return bytes;
}
(I'm aware I can do the same using BitConverter, but I want to compare the performance of the two)
Whether this will perform better than alternatives I don't know but the correct syntax is like this:
*((int)pointer + 1) = value2;
This:
*(int)pointer + 4 = value2;
gives an error because this: *(int)pointer is a variable reference and thus your code really looks like this:
i + 4 = value2;
which is not legal syntax in C#.
Instead encapsulate the addition to the address before dereferencing it into a variable reference (an lvalue if you want to google for these things):
*((int)pointer + 1)
+4 is also incorrect since the pointer is a "pointer to int", not a "pointer to byte", which means that +X is really +X * sizeof(int) in terms of byte-level addressing.
Your final method should look like this:
private static unsafe byte[] ToBytes(int value1, int value2)
{
var bytes = new byte[8];
fixed (byte* pointer = bytes)
{
*(int*)pointer = value1;
*((int*)pointer + 1) = value2;
}
return bytes;
}
Related
I want to use my laptop to communicate with MES(Manufacturing Execution System).
And when I serialized the data (struct type), something happen.
The code below is what I have done:
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct DataPackage
{
public int a;
public ushort b;
public byte c;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)] public string d;
}
class Program
{
static void Main(string[] args)
{
DataPackage pack1 = new DataPackage();
pack1.a = 0x33333301;
pack1.b = 200;
pack1.c = 21;
pack1.d = "hello";
byte[] pack1_serialized = getBytes(pack1);
Console.WriteLine(BitConverter.ToString(pack1_serialized));
byte[] getBytes(DataPackage str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
}
}
And here is the outcome:
I want the outcome to be like this:
33-33-33-01-00-C8-15-68-65-6C-6C-6F
So the questions are:
Why is the uint / ushort type data reverse after Marshalling?
Is there any other way that I can send the data in the sequence that I want ?
Why is the last word "o" in string "hello" disappear in the byte array ?
Thanks.
1 - Because your expected outcome is big endian, and your system appears to use little endian, so basically reversed order of bytes compared to what you expect.
2- Easiest way is to "convert" your numbers to big endian before marshalling (that is change them in a way which will produce desired result while converting them using little endian), for example like this:
static int ToBigEndianInt(int x) {
if (!BitConverter.IsLittleEndian)
return x; // already fine
var ar = BitConverter.GetBytes(x);
Array.Reverse(ar);
return BitConverter.ToInt32(ar, 0);
}
static ushort ToBigEndianShort(ushort x) {
if (!BitConverter.IsLittleEndian)
return x; // already fine
var ar = BitConverter.GetBytes(x);
Array.Reverse(ar);
return BitConverter.ToUInt16(ar, 0);
}
And then:
pack1.a = ToBigEndianInt(0x33333301);
pack1.b = ToBigEndianShort(200);
Note that this way of conversion is not very efficient and if you need more perfomance you can do this with some bit manipulations.
3 - Because string is null terminated, and this null terminator counts in SizeConst. Since you have it 5, there will be 4 characters of your string + 1 null terminator. Just increase SizeConst = 6 (that might add additional zeroes at the end because of Pack = 4).
i really need your help to port this c# code to Delphi one :
public unsafe byte[] Encode(byte[] inputPcmSamples, int sampleLength, out int encodedLength)
{
if (disposed)
throw new ObjectDisposedException("OpusEncoder");
int frames = FrameCount(inputPcmSamples);
IntPtr encodedPtr;
byte[] encoded =new byte [MaxDataBytes];
int length = 0;
/* How this can be ported to delphi */
fixed (byte* benc = encoded)
{
encodedPtr = new IntPtr((void*)benc);
length = API.opus_encode(_encoder, inputPcmSamples, frames, encodedPtr, sampleLength);
}
encodedLength = length;
if (length < 0)
throw new Exception("Encoding failed - " + ((Errors)length).ToString());
return encoded;
}
The main code part that i'm looking for is :
fixed (byte* benc = encoded)
{
encodedPtr = new IntPtr((void*)benc);
/* API.opus_encode = is declared in an other Class */
length = API.opus_encode(_encoder, inputPcmSamples, frames, encodedPtr, sampleLength);
}
many thanks
You seem to want to know how to deal with the fixed block in the C#.
byte[] encoded =new byte [MaxDataBytes];
....
fixed (byte* benc = encoded)
{
encodedPtr = new IntPtr((void*)benc);
length = API.opus_encode(_encoder, inputPcmSamples, frames, encodedPtr, sampleLength);
}
This use of fixed is to pin the managed array to obtain a pointer to be passed to the unmanaged code.
In Delphi we just want an array of bytes, and a pointer to that array. That would look like this:
var
encoded: TBytes;
....
SetLength(encoded, MaxDataBytes);
....
length := opus_encode(..., Pointer(encoded), ...);
or perhaps:
length := opus_encode(..., PByte(encoded), ...);
or perhaps:
length := opus_encode(..., #encoded[0], ...);
depending on how you declared the imported function opus_encode and your preferences.
If MaxDataBytes was a small enough value for the buffer to live on the stack, and MaxDataBytes was known at compile time, then a fixed length array could be used.
I have an int array of bits (length always 64) like:
1110000100000110111001000001110010011000110011111100001011100100
and I want to write it in one Int64 (or ulong?) variable. How to do it?
I tried to create a BitArray and then get int, but it throws System.ArgumentException, on CopyTo line:
private static Int64 GetIntFromBitArray(BitArray bitArray) {
var array = new Int64[1];
bitArray.CopyTo(array, 0);
return array[0];
}
That is because as mentioned in the documentation,
The specified array must be of a compatible type. Only bool, int, and byte types of arrays are supported.
So you could do something like this: (not tested)
private static long GetIntFromBitArray(BitArray bitArray)
{
var array = new byte[8];
bitArray.CopyTo(array, 0);
return BitConverter.ToInt64(array, 0);
}
Looking at the implementation of BitArray.CopyTo, it would be faster to copy the bits into an int[] (and then build the long from its two halves), that could look something like this: (also not tested)
private static long GetIntFromBitArray(BitArray bitArray)
{
var array = new int[2];
bitArray.CopyTo(array, 0);
return (uint)array[0] + ((long)(uint)array[1] << 32);
}
Casts to uint are to prevent sign-extension.
I've been trying to figure out whether it is possible to marshal a part of a struct into an array of bytes without any errors. The reason for this is because the part not going to be marshalled has a variable sized array. This is the the code I'm using.
C#:
public struct Random {
[MarshalAs(UnmanagedType.I4)]
public int a;
[MarshalAs(UnmanagedType.I4)]
public int b;
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD)]
public Random1[] r;
}
public struct Random1 {
[MarshalAs(UnmanagedType.I4)]
public int c;
}
private void Form1_Load(object sender, EventArgs e) {
int size = Marshal.SizeOf(typeof(Random));
int s = 4;
Random r = new Random();
Random r1 = new Random();
r.a = 1;
r.b = 5;
r.r = new Random1[2];
r.r[0].c = 10;
r.r[1].c = 12;
IntPtr p = Marshal.AllocHGlobal(size);
try {
byte[] arr = new byte[size];
Marshal.StructureToPtr(r, p, false);
Marshal.Copy(p, arr, 0, 8);
Marshal.FreeHGlobal(p);
p = Marshal.AllocHGlobal(size);
Marshal.Copy(arr, 0, p, 8);
r1 = (Random) Marshal.PtrToStructure(p, typeof(Random));
Marshal.FreeHGlobal(p);
p = IntPtr.Zero;
Debug.WriteLine(r1.a);
Debug.WriteLine(r1.b);
Debug.WriteLine(r1.r[0].c);
Debug.WriteLine(r1.r[1].c);
} finally {
if (p != IntPtr.Zero) {
Marshal.FreeHGlobal(p);
}
}
}
When I try this code it gives me an ArgumentException in the StructureToPtr. What am I doing wrong or can this be done? If not I've read something about using IntPtr. Could someone tell me how to do this?
I've been thinking long and hard about this one, and after trying several (very hackish) options, I have arrived at the conclusion that what you are doing is not possible.
First of all, it isn't possible to directly marshal an array of variable length, because no meaningful size offset can be computed by the Marshal, and therefore the memory layout can not be determined.
If the struct wouldn't contain any non-blittable, non-primitive types, you could theoretically do something like this:
byte[] buffer = new byte[8];
Marshal.Copy(new IntPtr(&r), buffer, 0, 8);
IntegersOnlyStruct partialStruct;
fixed (byte* b = buffer)
partialStruct = *(IntegersOnlyStruct*) b;
And obtain the two integers contained in the struct that way. However, since your Random1 is a non-primitive, non-blittable type this approach won't get you very far either.
The IntPtr approach to keep a pointer to a memory location where your Random1 struct is kept in memory is an alternative that could possibly work, but I haven't gone in-depth on that, yet.
I think you may want to re-think the way you approach this, as it's not possible in its current form. If anybody can prove otherwise, I'd be happy to see how it can be done.
Is there a way of mapping data collected on a stream or array to a data structure or vice-versa?
In C++ this would simply be a matter of casting a pointer to the stream as a data type I want to use (or vice-versa for the reverse)
eg: in C++
Mystruct * pMyStrct = (Mystruct*)&SomeDataStream;
pMyStrct->Item1 = 25;
int iReadData = pMyStrct->Item2;
obviously the C++ way is pretty unsafe unless you are sure of the quality of the stream data when reading incoming data, but for outgoing data is super quick and easy.
Most people use .NET serialization (there is faster binary and slower XML formatter, they both depend on reflection and are version tolerant to certain degree)
However, if you want the fastest (unsafe) way - why not:
Writing:
YourStruct o = new YourStruct();
byte[] buffer = new byte[Marshal.SizeOf(typeof(YourStruct))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(o, handle.AddrOfPinnedObject(), false);
handle.Free();
Reading:
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
o = (YourStruct)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(YourStruct));
handle.Free();
In case lubos hasko's answer was not unsafe enough, there is also the really unsafe way, using
pointers in C#. Here's some tips and pitfalls I've run into:
using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
// Use LayoutKind.Sequential to prevent the CLR from reordering your fields.
[StructLayout(LayoutKind.Sequential)]
unsafe struct MeshDesc
{
public byte NameLen;
// Here fixed means store the array by value, like in C,
// though C# exposes access to Name as a char*.
// fixed also requires 'unsafe' on the struct definition.
public fixed char Name[16];
// You can include other structs like in C as well.
public Matrix Transform;
public uint VertexCount;
// But not both, you can't store an array of structs.
//public fixed Vector Vertices[512];
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct Matrix
{
public fixed float M[16];
}
// This is how you do unions
[StructLayout(LayoutKind.Explicit)]
unsafe struct Vector
{
[FieldOffset(0)]
public fixed float Items[16];
[FieldOffset(0)]
public float X;
[FieldOffset(4)]
public float Y;
[FieldOffset(8)]
public float Z;
}
class Program
{
unsafe static void Main(string[] args)
{
var mesh = new MeshDesc();
var buffer = new byte[Marshal.SizeOf(mesh)];
// Set where NameLen will be read from.
buffer[0] = 12;
// Use Buffer.BlockCopy to raw copy data across arrays of primitives.
// Note we copy to offset 2 here: char's have alignment of 2, so there is
// a padding byte after NameLen: just like in C.
Buffer.BlockCopy("Hello!".ToCharArray(), 0, buffer, 2, 12);
// Copy data to struct
Read(buffer, out mesh);
// Print the Name we wrote above:
var name = new char[mesh.NameLen];
// Use Marsal.Copy to copy between arrays and pointers to arrays.
unsafe { Marshal.Copy((IntPtr)mesh.Name, name, 0, mesh.NameLen); }
// Note you can also use the String.String(char*) overloads
Console.WriteLine("Name: " + new string(name));
// If Erik Myers likes it...
mesh.VertexCount = 4711;
// Copy data from struct:
// MeshDesc is a struct, and is on the stack, so it's
// memory is effectively pinned by the stack pointer.
// This means '&' is sufficient to get a pointer.
Write(&mesh, buffer);
// Watch for alignment again, and note you have endianess to worry about...
int vc = buffer[100] | (buffer[101] << 8) | (buffer[102] << 16) | (buffer[103] << 24);
Console.WriteLine("VertexCount = " + vc);
}
unsafe static void Write(MeshDesc* pMesh, byte[] buffer)
{
// But byte[] is on the heap, and therefore needs
// to be flagged as pinned so the GC won't try to move it
// from under you - this can be done most efficiently with
// 'fixed', but can also be done with GCHandleType.Pinned.
fixed (byte* pBuffer = buffer)
*(MeshDesc*)pBuffer = *pMesh;
}
unsafe static void Read(byte[] buffer, out MeshDesc mesh)
{
fixed (byte* pBuffer = buffer)
mesh = *(MeshDesc*)pBuffer;
}
}
if its .net on both sides:
think you should use binary serialization and send the byte[] result.
trusting your struct to be fully blittable can be trouble.
you will pay in some overhead (both cpu and network) but will be safe.
If you need to populate each member variable by hand you can generalize it a bit as far as the primitives are concerned by using FormatterServices to retrieve in order the list of variable types associated with an object. I've had to do this in a project where I had a lot of different message types coming off the stream and I definitely didn't want to write the serializer/deserializer for each message.
Here's the code I used to generalize the deserialization from a byte[].
public virtual bool SetMessageBytes(byte[] message)
{
MemberInfo[] members = FormatterServices.GetSerializableMembers(this.GetType());
object[] values = FormatterServices.GetObjectData(this, members);
int j = 0;
for (int i = 0; i < members.Length; i++)
{
string[] var = members[i].ToString().Split(new char[] { ' ' });
switch (var[0])
{
case "UInt32":
values[i] = (UInt32)((message[j] << 24) + (message[j + 1] << 16) + (message[j + 2] << 8) + message[j + 3]);
j += 4;
break;
case "UInt16":
values[i] = (UInt16)((message[j] << 8) + message[j + 1]);
j += 2;
break;
case "Byte":
values[i] = (byte)message[j++];
break;
case "UInt32[]":
if (values[i] != null)
{
int len = ((UInt32[])values[i]).Length;
byte[] b = new byte[len * 4];
Array.Copy(message, j, b, 0, len * 4);
Array.Copy(Utilities.ByteArrayToUInt32Array(b), (UInt32[])values[i], len);
j += len * 4;
}
break;
case "Byte[]":
if (values[i] != null)
{
int len = ((byte[])values[i]).Length;
Array.Copy(message, j, (byte[])(values[i]), 0, len);
j += len;
}
break;
default:
throw new Exception("ByteExtractable::SetMessageBytes Unsupported Type: " + var[1] + " is of type " + var[0]);
}
}
FormatterServices.PopulateObjectMembers(this, members, values);
return true;
}