struct and byte[]

179 views
Skip to first unread message

William Stacey [MVP]

unread,
Jun 2, 2002, 10:33:32 PM6/2/02
to
This has been vexing me for a while. I want to take a struct (could be any
struct with char[]'s etc, but use following as an easy example) and easily
and quickly turn that into a byte array to pass to something like
udpClient.Send. Obviously the fastest would be to not copy to a byte[] at
all, but to somehow cast a byte[] onto the struct and just read from same
place in memory without a copy - If this is possible, please let me know.
The following is close, but does not work because the udpClient.Send does
not take a pointer to a byte. I would rather not manually build the byte[]
using some kind of stream because I think that would complicate the code and
be slower (but if only way, that is ok too) This has to be a common task
needed in almost any network program - is there a fast and standard way to
do this? TIA

struct Point1
{
public int x, y;

public Point1(int p1, int p2)
{
x = p1;
y = p2;
}
}
...

Point1 myPoint = new Point1(1,2);
byte[] buffer = new byte[sizeof(Point1)];
fixed (byte* pBuffer = buffer)
{
*((Point1*) pBuffer) = myPoint;
udpClient.Send (pBuffer, buffer.Length); //Error - pBuffer not byte[]
}

--
William Stacey, MCSE
Windows Server MVP


Greg Ewing

unread,
Jun 2, 2002, 10:59:38 PM6/2/02
to
William, you can use a BinaryFormatter to format your struct into a Byte[].
See the post by Herve on 5/30 titled "overloaded "Socket.receive"" for
someone else who is trying to do something similar.

--
Greg
http://www.claritycon.com/

"William Stacey [MVP]" <sta...@mvps.org> wrote in message
news:ekto0bqCCHA.2576@tkmsftngp04...

William Stacey [MVP]

unread,
Jun 2, 2002, 11:29:51 PM6/2/02
to
Thanks Greg, however I don't think the BinaryFormatter is what I'm after.
This seems like a lot of overhead and It looks like it may add metadata to
the stream (for the rebuild at the other end - not sure.) My byte stream
must be formatted in a specific way to follow rfc. There must be a fast way
to do this with a struct and unsafe code or something. So close but far
away. Any other ideas?

--
William Stacey, MCSE
Windows Server MVP


"Greg Ewing" <gewing@_NO_SPAM_claritycon.com> wrote in message
news:#lh$aqqCCHA.2072@tkmsftngp02...

Chris R

unread,
Jun 3, 2002, 1:56:35 AM6/3/02
to
struct Point1
{
// only one 'size' created, regardless of how many Point1s are created.
public const int size = 8;
public int x, y;

public Point1(int p1, int p2)
{
x = p1;
y = p2;
}

public byte [] GetBytes( )
{
byte [] retArray = new byte[ size ];
Buffer.BlockCopy( BitConverter.GetBytes(x), 0, retArray, 0, 4 );
Buffer.BlockCopy( BitConverter.GetBytes(y), 0, retArray, 4, 4 );
// For larger structures, keep on adding to the struct.
return retArray;


}
}
...
Point1 myPoint = new Point1(1,2);

// Note the use of Point1.size, not myPoint.size
udpClient.Send( myPoint.GetBytes(), Point1.size );

Hope this helps,
Chris R

"William Stacey [MVP]" <sta...@mvps.org> wrote in message
news:ekto0bqCCHA.2576@tkmsftngp04...

NETMaster

unread,
Jun 3, 2002, 4:28:50 AM6/3/02
to
does it work if
udpClient.Send (pBuffer, buffer.Length);
is changed to
udpClient.Send ( buffer, buffer.Length); ?


Note, if the struct contains any array[],
unsafe/fixed will get error
"Cannot take the address or size of a variable of a managed type"

then you could use Marshal & GCHandle like:


// ===============================================================
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
struct YourStruct
{
[MarshalAs( UnmanagedType.ByValArray, SizeConst=8 )]
public char[] txt;
public int num;
}
...

// usage:
YourStruct s;
s.txt = "TestText".ToCharArray();
s.num = 77;

// serialize:
byte[] a = RawSerializeEx( s );

// reverse = deserialize:
YourStruct sr = (YourStruct) RawDeserializeEx( a, typeof(YourStruct) );


public static object RawDeserializeEx( byte[] rawdatas, Type anytype )
{
int rawsize = Marshal.SizeOf( anytype );
if( rawsize > rawdatas.Length )
return null;
GCHandle handle = GCHandle.Alloc( rawdatas, GCHandleType.Pinned );
IntPtr buffer = handle.AddrOfPinnedObject();
object retobj = Marshal.PtrToStructure( buffer, anytype );
handle.Free();
return retobj;
}

public static byte[] RawSerializeEx( object anything )
{
int rawsize = Marshal.SizeOf( anything );
byte[] rawdatas = new byte[ rawsize ];
GCHandle handle = GCHandle.Alloc( rawdatas, GCHandleType.Pinned );
IntPtr buffer = handle.AddrOfPinnedObject();
Marshal.StructureToPtr( anything, buffer, false );
handle.Free();
return rawdatas;
}
// ===============================================================


--
NETMaster (Thomas Scheidegger)
http://www.cetus-links.org/oo_csharp.html

"William Stacey [MVP]" <sta...@mvps.org> wrote in message news:ekto0bqCCHA.2576@tkmsftngp04...

> This has been vexing me for a while. I want to take a struct (could be any
> struct with char[]'s etc, but use following as an easy example) and easily
> and quickly turn that into a byte array to pass to something like
> udpClient.Send. Obviously the fastest would be to not copy to a byte[] at
> all, but to somehow cast a byte[] onto the struct and just read from same
> place in memory without a copy - If this is possible, please let me know.
> The following is close, but does not work because the udpClient.Send does
> not take a pointer to a byte. I would rather not manually build the byte[]
> using some kind of stream because I think that would complicate the code and
> be slower (but if only way, that is ok too) This has to be a common task
> needed in almost any network program - is there a fast and standard way to
> do this? TIA
> struct Point1
> {
> public int x, y;
>
> public Point1(int p1, int p2)
> {
> x = p1;
> y = p2;
> }
> }

William Stacey [MVP]

unread,
Jun 3, 2002, 9:46:49 AM6/3/02
to
Thanks Chris! That will come in handy.

--
William Stacey, MCSE
Windows Server MVP


"Chris R" <sot...@bellsouth.net> wrote in message
news:lnDK8.1402$_p6....@e3500-atl1.usenetserver.com...

William Stacey [MVP]

unread,
Jun 3, 2002, 10:15:23 AM6/3/02
to
Thanks Thomas! That is probably exactly what I wanted as I will be using
char[]'s too.
BTW - Marshal.StructureToPtr says:
"A managed object holding the data to be marshaled. This object must be an
instance of a formatted class."

What is a formatted class? This is only referenced in the Marshal class
unless my search is not picking it up elsewhere.

--
William Stacey, MCSE
Windows Server MVP


"NETMaster" <spam.ne...@swissonline.ch> wrote in message
news:e10$YitCCHA.2296@tkmsftngp05...

NETMaster

unread,
Jun 3, 2002, 12:27:22 PM6/3/02
to
> What is a formatted class?

I guess formatted = 'fixed layout' :
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconcopyingpinning.asp
and I assume must have [StructLayout].

--
NETMaster (Thomas Scheidegger)
http://www.cetus-links.org/oo_csharp.html


"William Stacey [MVP]" <sta...@mvps.org> wrote in message news:eaRxCkwCCHA.2628@tkmsftngp05...

NETMaster

unread,
Jun 3, 2002, 12:30:20 PM6/3/02
to
> What is a formatted class?

.. and here the real description:
http://msdn.microsoft.com/library/en-us/cpguide/html/cpcondefaultmarshalingforvaluetypes.asp


"A formatted type is a complex type that contains information that explicitly
controls the layout of its members in memory.
The member layout information is provided using the StructLayoutAttribute attribute.
The layout can be one of the following LayoutKind enumeration values:"...

--
NETMaster (Thomas Scheidegger)
http://www.cetus-links.org/oo_csharp.html

"William Stacey [MVP]" <sta...@mvps.org> wrote in message news:eaRxCkwCCHA.2628@tkmsftngp05...

Eric Gunnerson [MS]

unread,
Jun 3, 2002, 12:51:13 PM6/3/02
to
You can do this directly using unsafe. I did a few helper classes for my
implementation of Spacewar! - take a look on the team site below, and you'll
find the source there.

--
Visit the C# product team at http://www.gotdotnet.com/team/csharp

This posting is provided "AS IS" with no warranties, and confers no rights.

"William Stacey [MVP]" <sta...@mvps.org> wrote in message

news:ekto0bqCCHA.2576@tkmsftngp04...

Chris R

unread,
Jun 3, 2002, 2:28:19 PM6/3/02
to
// I admit, I have to get over my avoidance of the "unsafe" keyword.
// It can be extremely useful, so I took Erics reply and worked out the
following:

...
Point1 myPoint = new Point1(1,2);

sendPoint( ref myPoint );
...

private unsafe void sendPoint( ref Point1 myPoint )
{
fixed( Point1* pPoint1 = &myPoint )
{
byte* pBuffer = (byte*)pPoint1;


udpClient.Send (pBuffer, buffer.Length); //Error - pBuffer not
byte[]
}
}

Chris R.

"Eric Gunnerson [MS]" <eri...@online.microsoft.com> wrote in message
news:O5$sF7xCCHA.1732@tkmsftngp02...

Chris R

unread,
Jun 3, 2002, 2:30:58 PM6/3/02
to
OK, so I didn't write the udpClient part in my test code... so
buffer.Length
should be
sizeof( myPoint )

or something similar.

"Chris R" <sot...@bellsouth.net> wrote in message

news:ZvOK8.4038$EW5.4...@e3500-atl2.usenetserver.com...

Chris R

unread,
Jun 3, 2002, 3:10:48 PM6/3/02
to
Never mind...
I'm still thinking in C++ where a byte [] and a byte* mean the same
thing... so I screwed up that program...
It seems it is a requirement that the memory has to be copied for this
to work, unless I'm still missing something, but at least I can do it in one
line;

private unsafe void sendPoint( ref Point1 myPoint )
{

int pointSize = sizeof(Point1);
byte [] arBuffer = new byte[ pointSize ];


fixed( Point1* pPoint1 = &myPoint )
{

fixed( byte* pBuf = arBuffer )
{
Point1* ps = pPoint1;
Point1* pd = (Point1*)pBuf;
*((Point1*)pd) = *((Point1*)ps);
udpClient.Send( arBuffer, pointSize );
}
}
}


"Chris R" <sot...@bellsouth.net> wrote in message
news:ZvOK8.4038$EW5.4...@e3500-atl2.usenetserver.com...

Chris R

unread,
Jun 3, 2002, 3:44:47 PM6/3/02
to
I still like the idea of creating a more general method that can be
transferred from struct to struct, so after making a mess of things lower in
the thread, I went back to this concept. For any struct, you can just
change the type in the function and have your bytes and eat it too. If C#
gets generics (C++ templates) and applies them to structs, this would be
even easier.

I went ahead and put the struct size in the method, but that's not
necessary, of course, but it saved me from having to write another method or
a property and preserves the data in Point1 as being simply the information
it needs.

*****************************************
struct Point1
{
...
public unsafe byte [] GetBytes( out int structSize )
{
structSize = sizeof( Point1 );
byte [] retArray = new byte[ structSize ];
fixed( Point1* pPoint1 = &this )
{
fixed( byte* pBuf = retArray )


{
Point1* ps = pPoint1;
Point1* pd = (Point1*)pBuf;
*((Point1*)pd) = *((Point1*)ps);
}
}

return retArray;
}
}
*****************************************


Point1 myPoint = new Point1(1,2);

int pointSize;
udpClient.Send( myPoint.GetBytes( out pointSize ), pointSize );

Chris R.

"Chris R" <sot...@bellsouth.net> wrote in message

news:lnDK8.1402$_p6....@e3500-atl1.usenetserver.com...

William Stacey [MVP]

unread,
Jun 3, 2002, 4:24:30 PM6/3/02
to
That is kinda clean, then the class gets to "keep all its data."
Thanks Chris and Eric :-)

--
William Stacey, MCSE
Microsoft MVP Windows 2000/NT Server

"Chris R" <sot...@bellsouth.net> wrote in message

news:GDPK8.4383$EW5.4...@e3500-atl2.usenetserver.com...

Chris R

unread,
Jun 3, 2002, 4:55:01 PM6/3/02
to
Heh, as I read your reply and looked at the code again, I laughed at
myself,
*((Point1*)pd) = *((Point1*)ps);
should be:

*pd = *ps;
since pd and ps are already Point1*. Redundant casting. I'd originally
written them as byte*, but that would have needed a for loop, so I changed
it to Point1*, but forgot to reevaluate that line. :o)

Chris R.

"William Stacey [MVP]" <sta...@mvps.org> wrote in message

news:#9fYRyzCCHA.2440@tkmsftngp05...

William Stacey [MVP]

unread,
Jun 3, 2002, 5:33:00 PM6/3/02
to
Thanks Eric. Could you get me close to the code your thinking about - you
have many *.cs files to look over there.

--
William Stacey, MCSE
Microsoft MVP Windows 2000/NT Server

"Eric Gunnerson [MS]" <eri...@online.microsoft.com> wrote in message
news:O5$sF7xCCHA.1732@tkmsftngp02...

Chris R

unread,
Jun 3, 2002, 7:37:14 PM6/3/02
to
William,

In SpaceWar, take a look at PtrHolder.cs for a lot of pointer
methodology. I'm going to check it out now and see what I can learn.

Chris R.

"William Stacey [MVP]" <sta...@mvps.org> wrote in message

news:OAC5iY0CCHA.1880@tkmsftngp04...

Reply all
Reply to author
Forward
0 new messages