Read 16-bit block as a 32-bit int

D

duylam76

I'm programming a server and corresponding client application that
sends data to each other over a socket. I want to encode an integer to
send over the socket. Right now everything is fine because everyone
using our app has an integer encoded as 32 bits. I'm not sure what
might happen should someone use a machine/OS that uses 64 bit
integers, however.

For instance, say that I know for certain that our server uses 32 bit
integers. I can send an integer across the socket as 4 bytes, and read
it on the client side directly by dereferencing an int pointer
pointing at the first of the four bytes read off. If the client side
uses 64 bits for an integer, however, directly reading it using an int
pointer won't really work (the pointer dereference will look for 8
bytes instead of 4).

Since I don't have a 64 bit machine to test this, for theoretical
purposes I want to run a similar test to see what would happen if I
wanted instead to encode my integers as 16 bits (and read it as a 32
bit int).

How do I read a 16-bit block (a block within a simple byte array) and
store the number as a 32-bit integer?

For instance, say I have

char* buffer; // pointer to char buffer that stores some encoded
data
int a; // the integer I want to store in

.... and I know that the first two bytes in "buffer" contain the
encoding for a 16-bit integer. I want to read the first two bytes and
then store the value into the integer "a".

If the first FOUR bytes in "buffer" stored the int, I would be able to
do it easily:
a = *((int*) buffer);

So how would I be able to do this if only TWO bytes represented the
integer? Is there an entirely better way to read off a value other
than dereferencing an integer pointer? (Again, I'm only doing 16 and
32 because I can directly test it on my machine. But since my real
goal is to handle 32 and 64, any other advice regarding 32 bit or 64
bit data formats might be helpful too)

Duy Lam
 
N

Nelu

On Mar 28, 2:11 pm, (e-mail address removed) wrote:
For instance, say that I know for certain that our server uses 32 bit
integers. I can send an integer across the socket as 4 bytes, and read
it on the client side directly by dereferencing an int pointer
pointing at the first of the four bytes read off. If the client side
uses 64 bits for an integer, however, directly reading it using an int
pointer won't really work (the pointer dereference will look for 8
bytes instead of 4).

There are a number of things that can be different on different
machines (because of the hardware or the compiler) like:
- number of bits in a C byte
- padding bits
- integer representation
- endianess
Since I don't have a 64 bit machine to test this, for theoretical
purposes I want to run a similar test to see what would happen if I
wanted instead to encode my integers as 16 bits (and read it as a 32
bit int).

How do I read a 16-bit block (a block within a simple byte array) and
store the number as a 32-bit integer?

It depends on: number of bits in a C byte, padding bits, integer
representation, endianess...
For instance, say I have

char* buffer; // pointer to char buffer that stores some encoded
data
int a; // the integer I want to store in

... and I know that the first two bytes in "buffer" contain the
encoding for a 16-bit integer. I want to read the first two bytes and
then store the value into the integer "a".

You can't. Well, you can but you need to have platform and compiler
specific information.
If the first FOUR bytes in "buffer" stored the int, I would be able to
do it easily:
a = *((int*) buffer);

You can't unless you're absolutely sure that you can. :)
So how would I be able to do this if only TWO bytes represented the
integer? Is there an entirely better way to read off a value other
than dereferencing an integer pointer? (Again, I'm only doing 16 and
32 because I can directly test it on my machine. But since my real
goal is to handle 32 and 64, any other advice regarding 32 bit or 64
bit data formats might be helpful too)

Yes, convert the number to an ASCII string when you send it and from
ASCII to an integer when you receive it. Keep in mind to use the
INT_MAX value to make sure that you are not passing numbers that can
be represented on one machine but cannot be represented on another.
 
S

Stephen Sprunk

I'm programming a server and corresponding client application that
sends data to each other over a socket. I want to encode an integer to
send over the socket. Right now everything is fine because everyone
using our app has an integer encoded as 32 bits. I'm not sure what
might happen should someone use a machine/OS that uses 64 bit
integers, however.

Sockets are off-topic here, but the same issue arises when dealing with
binary data in files, so most of the answer is still topical.
For instance, say that I know for certain that our server uses 32 bit
integers. I can send an integer across the socket as 4 bytes, and read
it on the client side directly by dereferencing an int pointer
pointing at the first of the four bytes read off. If the client side
uses 64 bits for an integer, however, directly reading it using an int
pointer won't really work (the pointer dereference will look for 8
bytes instead of 4).

If you know the data is 32-bit, then use int32_t; that will be the same size
on every platform. If your platform doesn't have it (or something similar),
you've got bigger problems.

The other issue is endianness. Solving that portably is a mess, though
doable, but if you're on a system with sockets you'll have htonl() and
friends. Learn to use them.
For instance, say I have

char* buffer; // pointer to char buffer that stores some encoded
data
int a; // the integer I want to store in

... and I know that the first two bytes in "buffer" contain the
encoding for a 16-bit integer. I want to read the first two bytes and
then store the value into the integer "a".

a = ntohs(*(int16_t *)buffer);

and to send:

*(int16_t *)buffer = htons(a);
If the first FOUR bytes in "buffer" stored the int, I would be able to
do it easily:
a = *((int*) buffer);

a = ntohl(*(int32_t *)buffer);

and to send:

*(int32_t *)buffer = htonl(a);


Do note that in all of the above cases, you need to make sure buffer is
aligned correctly. If you can't ensure alignment, then you're probably best
off handling the data as individual bytes. For instance, reading a 32-bit
int from buffer would look like this:

a = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
But since my real goal is to handle 32 and 64, any other advice
regarding 32 bit or 64 bit data formats might be helpful too)

My advice is to actually sit down and define the wire protocol (i.e. file
format), and then figure out how to send/receive things that comply with it
on various platforms. Don't start with the implementation first.

S
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top