Convert a uint16_t to char[2] to be sent over sock

2019-03-15 15:05发布

问题:

I know that there are things out there roughly on this.. But my brains hurting and I can't find anything to make this work...

I am trying to send an 16 bit unsigned integer over a unix socket.. To do so I need to convert a uint16_t into two chars, then I need to read them in on the other end of the connection and convert it back into either an unsigned int or an uint16_t, at that point it doesn't matter if it uses 2bytes or 4bytes (I'm running 64bit, that's why I can't use unsigned int :)

I'm doing this in C btw

Thanks

回答1:

Why not just break it up into bytes with mask and shift?

 uint16_t value = 12345;
 char lo = value & 0xFF;
 char hi = value >> 8;

(edit)

On the other end, you assemble with the reverse:

 uint16_t value = lo | uint16_t(hi) << 8;

Off the top of my head, not sure if that cast is required.



回答2:

char* pUint16 = (char*)&u16;

ie Cast the address of the uint16_t.

char c16[2];
uint16_t ui16 = 0xdead;
memcpy( c16, ui16, 2 );

c16 now contains the 2 bytes of the u16. At the far end you can simply reverse the process.

char* pC16 = /*blah*/
uint16_t ui16;
memcpy( &ui16, pC16, 2 );

Interestingly though there is a call to memcpy nearly every compiler will optimise it out because its of a fixed size.

As Steven sudt points out you may get problems with big-endian-ness. to get round this you can use the htons (host-to-network short) function.

uint16_t ui16correct = htons( 0xdead );

and at the far end use ntohs (network-to-host short)

uint16_t ui16correct = ntohs( ui16 );

On a little-endian machine this will convert the short to big-endian and then at the far end convert back from big-endian. On a big-endian machine the 2 functions do nothing.

Of course if you know that the architecture of both machines on the network use the same endian-ness then you can avoid this step.

Look up ntohl and htonl for handling 32-bit integers. Most platforms also support ntohll and htonll for 64-bits as well.



回答3:

Sounds like you need to use the bit mask and shift operators.

To split up a 16-bit number into two 8-bit numbers:

  • you mask the lower 8 bits using the bitwise AND operator (& in C) so that the upper 8 bits all become 0, and then assign that result to one char.
  • you shift the upper 8 bits to the right using the right shift operator (>> in C) so that the lower 8 bits are all pushed out of the integer, leaving only the top 8 bits, and assign that to another char.

Then when you send these two chars over the connection, you do the reverse: you shift what used to be the top 8 bits to the left by 8 bits, and then use bitwise OR to combine that with the other 8 bits.



回答4:

Basically you are sending 2 bytes over the socket, that's all the socket need to know, regardless of endianness, signedness and so on... just decompose your uint16 into 2 bytes and send them over the socket.

char byte0 = u16 & 0xFF;
char byte1 = u16 >> 8;

At the other end do the conversion in the opposite way