Putting an int value in a char array

V

Vlad Dogaru

Hi everyone,

I'm trying to reliably store and read back an int (or short) into/from
a character array. How does one do this in C? I've thought about using
bit shifting and the like in order to put one char at a time, but this
doesn't seem right. Is there something I'm missing? If it's any help,
I'm trying to build a char array to send through a socket.

Thanks,
Vlad
 
B

Ben Bacarisse

Vlad Dogaru said:
I'm trying to reliably store and read back an int (or short) into/from
a character array. How does one do this in C?

memcpy(&char_buf, &int_var, sizeof int_var);
I've thought about using
bit shifting and the like in order to put one char at a time, but this
doesn't seem right. Is there something I'm missing? If it's any help,
I'm trying to build a char array to send through a socket.

Ah! Well you have a better method then. The above, being a memory
copy, is not right if you send data between systems with different byte
orderings. The shifting method (used on unsigned types) can give you
a portable solution.
 
T

Tomás Ó hÉilidhe

Ah!  Well you have a better method then.  The above, being a memory
copy, is not right if you send data between systems with different byte
orderings.  The shifting method (used on unsigned types) can give you
a portable solution.


Programs that do networking have functions to convert between "native
byte order" and "network byte order". Network byte order happens to be
big-endian, so on Motorolla machine it's a no-op, while on Intel
machines the bytes have to be re-arranged.

Your program should be able to play with bytes however it likes and
then rely on the conversion function to send them out in Network Byte
order.
 
V

Vlad Dogaru

memcpy(&char_buf, &int_var, sizeof int_var);
[snip]
The shifting method (used on unsigned types) can give you
a portable solution.

Would memcpy and htons & co be a correct approach? My problem is that
it's not only short ints that I have to accomodate, but also the
occasional long; I'd like to have a uniform handling of these
operations.

Also, I'm not sure if the way I found to "deserialize" these values is
safe and recommended:

x = htons(x);
memcpy(&buffer, &x, sizeof x);
/* Later, at the other end: */
x = ntohs(*((unsigned short *) buffer));

I only need unsigned values, so unsigned {short, long} should be
enough. And one final question: would there be any reason to using
uint16_t and uint32_t instead of unsigned short and unsigned long?

Thanks and sorry for the question avalanche,
Vlad
 
V

Vlad Dogaru

sprintf() will do the int -> string thing.
strtol() will do the string to int.

These are, indeed, a boon to programmers, but I need to send the
numbers in binary format.

Vlad
 
B

Ben Bacarisse

Vlad Dogaru said:
memcpy(&char_buf, &int_var, sizeof int_var);
[snip]
The shifting method (used on unsigned types) can give you
a portable solution.

Would memcpy and htons & co be a correct approach?

First htons and htnol (the "long" version) are POSIX, so technically
off topic here. They are an excellent choice for this problem but
they incur a cost that can be avoided if you are designing a system
for CPUs where the "host" representation is different to the "network"
one. If you can use you own functions, you can avoid this (probably
small) cost by making these operations "null" on your main platform.
My problem is that
it's not only short ints that I have to accomodate, but also the
occasional long; I'd like to have a uniform handling of these
operations.

Then there is htonl and ntohl that take uint32_t values. Note that C
does not insist that long is 32 bits, but uint32_t is.
Also, I'm not sure if the way I found to "deserialize" these values is
safe and recommended:

x = htons(x);
memcpy(&buffer, &x, sizeof x);

That is the safe, portable, way. However, a lot of code will be able
to define the buffer as struct with integer members, so one often
sees:

msg.data1 = htons(x);

or even, the more dangerous:

*(uint16_t *)buffer = htons(x);

The memcpy version avoids any alignment problems and so it more portable.
/* Later, at the other end: */
x = ntohs(*((unsigned short *) buffer));

The reverse would have been

memcpy(&x, &buffer, sizeof x);
x = htons(x);

but the dangerous cast is often used. Data formats in protocols are
often chosen so that there will be no alignment problems on most
common processors, so you will have to decide between portability,
code clarity and speed of packing knowing what you know about the
target systems and the purpose of the code.
I only need unsigned values, so unsigned {short, long} should be
enough. And one final question: would there be any reason to using
uint16_t and uint32_t instead of unsigned short and unsigned long?

Yes. The most important is that POSIX now defines the [nh]to[hn][ls]
functions in terms of these types. These days, you are more likely
to find a system where short > 16 bits or long > 32 bits than you are
to find one where uint32_t is either not defined or is hard to define
yourself.
 
V

Vlad Dogaru

Yes. The most important is that POSIX now defines the [nh]to[hn][ls]
functions in terms of these types. These days, you are more likely
to find a system where short > 16 bits or long > 32 bits than you are
to find one where uint32_t is either not defined or is hard to define
yourself.

Thank you for all your time, Ben.

Vlad
 

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
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top