Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SOS::Structs to Byte Arrays

59 views
Skip to first unread message

gautam zalpuri

unread,
Feb 9, 2001, 7:52:48 AM2/9/01
to
Hi!

I need to copy a structure into a byte array so that I can send it over a
socket. But I have been having *problems*.

Here is a runthru' of what I'm doing..
I need byte alignment - so I have the attributes defined before the struct.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
struct aStruct
{
public int field1;
public int field2;
public int field3;
public int field4;
}

However, when I have to convert the struct into a byte stream for writing to
the socket, I cannot figure out how to convert the struct to a byte array
except by converting the object to a string and then to a byte array - this
way I get the size of the struct as 32 bytes while it should be 16 bytes.

How do I get the exact no. of bytes?!!?

Please help!

Thanks
gautam

--
Realize your limitations. Then go beyond them.


Larry Moretz

unread,
Feb 9, 2001, 6:45:01 PM2/9/01
to
Strings in C# are always UNICODE (thank you rest of the world! 255
characters is enough for anybody). Each character in your string is
occupying 2 bytes.

"gautam zalpuri" <gautam...@netwala.com> wrote in message
news:OXDurepkAHA.2168@tkmsftngp03...

gautam zalpuri

unread,
Feb 10, 2001, 5:45:42 AM2/10/01
to
Gaah....UNICODE!!!!

Thanks for the quick reply....I did arrive at that conclusion too and what I
tried was to convert the string to ASCII. It still does'nt seem to work!!


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
struct aStruct
{
public int field1;
public int field2;
public int field3;
public int field4;
}

aStruct datastruct = new aStruct ();
//fill in the struct data....
//establish socket connection
Byte[] b=
System.Text.Encoding.ASCII.GetBytes(datastruct.ToString().ToCharArray());
//write to the socket

However, I still get the number of bytes in the byte array (b) as 32 (it
should be 16)
What am I doing wrong?!!

Thanks,
gautam

--
Realize your limitations. Then go beyond them.

"Larry Moretz" <mor...@dnb.com> wrote in message
news:eUedqwvkAHA.1524@tkmsftngp05...

Derek Harmon

unread,
Feb 11, 2001, 9:20:39 PM2/11/01
to
"gautam zalpuri" <gautam...@netwala.com> wrote in message news:OXDurepkAHA.2168@tkmsftngp03...
> However, when I have to convert the struct into a byte stream for writing to
> the socket, I cannot figure out how to convert the struct to a byte array
>

The straightforward way is to use the System.BitConverter class.

Note that BitConverter is currently little-endian (reverse byte order for backward
compatibility with older Intel microprocessors that had smaller word sizes). You
mentioned elsewhere that you were using this for a socket-based application, so
this may be important to you if you're communicating with Unix boxes (which are
largely Big Endian, unless they happen to be powered by an Intel processor).

See the following example,

- - -

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
struct MyStruct


{
public int field1;
public int field2;
public int field3;
public int field4;

// Convert to Byte Array Per Struct Field
//
public static Byte[] ToByteArray( ref MyStruct src)
{
Int32 _pos = 0;
Byte[] _dest = new Byte[ Marshal.SizeOf( src)];

MyStruct.CopyField( ref _pos, ref src.field1, _dest);
MyStruct.CopyField( ref _pos, ref src.field2, _dest);
MyStruct.CopyField( ref _pos, ref src.field3, _dest);
MyStruct.CopyField( ref _pos, ref src.field4, _dest);

return _dest;
}

// Subordinate method of ToByteArray( ) that uses BitConverter and
// Array.Copy( ) to pack field into dest at pos.
//
public static void CopyField( ref Int32 pos, ref Int32 field, byte[] dest)
{
Byte[] _fieldBytes = BitConverter.GetBytes( field);
Int32 _fieldLen = 4; // Marshal.SizeOf( Int32) == 4

Array.Copy( _fieldBytes, 0, dest, pos, _fieldLen);
pos = pos + _fieldLen;
}
}

public class App
{
public static void Main()
{
MyStruct _before;
Byte[] _after;
Int32 _pos = 0;

// Initialize fields before conversion.
//
_before.field1 = 65;
_before.field2 = 66;
_before.field3 = 67;
_before.field4 = 68;

// Initialize byte array to result of conversion.
//
_after = MyStruct.ToByteArray( ref _before);

// Poor Man's Hex Dump
//
Console.WriteLine( "_after.Length = {0}", _after.Length);
while ( _pos < _after.Length)
{
Console.Write( "{0:X2} ", _after[ _pos]);
++_pos;
}
}
}

- - -

BitConverter has been hackneyed lately in this newsgroup, so I won't harp on
this example for too long. It has the glaring disadvantage of requiring knowledge
about the makeup of the structure. It also puts you at the mercy of BitConverter
being little-endian, which may be unacceptable. It's strengths are that it's reason-
ably efficient and direct.

The easiest way to remove the intimacy between ToByteArray( ) and MyStruct
is to use of reflection. Here's an alternate solution,

add a using System.Reflection; statement.

remove the definition of CopyField( ).

replace ToByteArray( ) with the following definition,

- - -

public static Byte[] ToByteArray( ref MyStruct src)
{
Int32 _len = Marshal.SizeOf( src);
Byte[] _dest = new Byte[ _len];
Type _srcType = src.GetType();
FieldInfo[] _fields = _srcType.GetFields();

Int32 _pos = 0, _fieldLen;
UInt64 _qwValue; // supports arbitrary valuetypes up to 8 bytes

foreach ( FieldInfo _fi in _fields)
{
_fieldLen = Marshal.SizeOf( _fi.FieldType);

// Int32 implements IConvertible, a straight cast won't work.
//
_qwValue = ((IConvertible)(_fi.GetValue( src))).ToUInt64();

while ( _pos < _len && --_fieldLen >= 0)
{
// little endian qword-to-byte conversion, you can replace
// with a Big Endian conversion if necessary.
//
_dest[ _pos] = (Byte) ( _qwValue & 0xFF);
_qwValue = _qwValue >> 8;
++_pos;
}
}
return _dest;
}

- - -

This reflects upon the fields of the structure, it's much more generic and can
be applied to multiple structures composed of value types (not just Int32's,
although with the first solution you could approach this capability with
a floatilla of overloaded CopyField( ) methods.)

The alternate solution also exposes the bit conversion logic within the while
loop, packing byte-by-byte from a quadword. It's easy to replace with the
Big Endian conversion, although it's a double edged cutlass because it reveals
the details BitConverter was created to hide.

All this genericity comes with a small cost in efficiency, so these are trade-offs
you'll have to assess in your implementation.

A third solution is available to us that grapples with your problem at the lowest
levels, it's the most C-like in it's appearance ... it's *unsafe*. If efficiency pertains
to you, then no matter how you dance around on the framework, the type of
access you need is beneath the floorboards.

See the following example, again, only ToByteArray( ) needs to be replaced,
you can remove "using System.Reflection;"

- - -

// Notice the unsafe keyword.
//
public static unsafe byte[] ToByteArray( ref MyStruct src)
{
Int32 _len = Marshal.SizeOf( src);
Byte[] _dest = new Byte[ _len];

// These are moveable addresses, so you need to lock them down
// with the fixed keyword. I prefer the readability of &_dest[i] over
// the the implicit degeneration of an array to a pointer.
//
fixed ( Byte* _pSource = (Byte*)&src , _pDest = &_dest[0] )
{
// Counting backwards just to save an extra local variable, plus
// comparisons with 0 tend to be faster. Don't let this celeritous
// hack obscure the point.
//
while ( --_len >= 0 )
{
_pDest[ _len] = _pSource[ _len];
}
}
return _dest;
}

- - -

Now, this still isn't optimal, the while loop could approach a speed
improvement of four if it copied 32 bits at a time instead of 8. But
I think you get the idea.

This solution implicitly follows the underlying platform's endian-ness.

Closely coupled field-by-field with BitConverter, generic with reflection,
or Kernigan-esque with the unsafe and fixed keywords, at least now you
have a choice. :-)


Derek Harmon

gautam zalpuri

unread,
Feb 12, 2001, 12:27:26 AM2/12/01
to
Hi Derek!

It works!!
I do appreciate the effort you have put in into the explanation - made my
job a copy paste one. :-)

Thank you ever so much!
Best Regards
gautam

--
Realize your limitations. Then go beyond them.


"Derek Harmon" <lore...@msn.com> wrote in message
news:O3eoqqJlAHA.2156@tkmsftngp05...

0 new messages