90

Hey, I'm looking to convert a int that is inputed by the user into 4 bytes, that I am assigning to a character array. How can this be done?

Example:

Convert a user inputs of 175 to

00000000 00000000 00000000 10101111


Issue with all of the answers so far, converting 255 should result in 0 0 0 ff although it prints out as: 0 0 0 ffffffff

unsigned int value = 255;   

buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;

union {
    unsigned int integer;
    unsigned char byte[4];
} temp32bitint;

temp32bitint.integer = value;
buffer[8] = temp32bitint.byte[3];
buffer[9] = temp32bitint.byte[2];
buffer[10] = temp32bitint.byte[1];
buffer[11] = temp32bitint.byte[0];

both result in 0 0 0 ffffffff instead of 0 0 0 ff

Just another example is 175 as the input prints out as 0, 0, 0, ffffffaf when it should just be 0, 0, 0, af

betabandido
  • 18,946
  • 11
  • 62
  • 76
Jacob Nelson
  • 2,946
  • 5
  • 33
  • 41
  • 6
    How is your buffer[] defined? An unsigned byte with a value greater than 127 has the most-significant bit set. This signifies a negative number when using a signed byte. Your FFFFFFFF looks like a sign-extended interpretation of a 0xFF byte. – Blastfurnace Sep 24 '10 at 06:16
  • You should use the format %hhx to print your numbers. – Jens Gustedt Sep 24 '10 at 06:22
  • ..but note that `%hhx` is a C99 addition. – caf Sep 24 '10 at 06:40
  • 2
    Nit: you have no guarantee that 4 bytes are necessary and sufficient for holding an int. You need `sizeof (int)` bytes. – pmg Sep 24 '10 at 08:33
  • To those who might encounter this post: the only correct solution is to use bit shift on unsigned types as in the accepted answer. You can read that one and stop there. It is both the fastest and most portable version. `memcpy` on unsigned types is ok if all types are unsigned and endianess has been taken in account. union solutions are not ok, they are non-portable - why write non-portable code when you can get portable code with the same effort? Pointer arithmetic solutions are not ok, they are possibly slow, definitely non-portable and often invoke poorly-specified behavior. – Lundin Mar 13 '19 at 13:53

10 Answers10

171

The portable way to do this (ensuring that you get 0x00 0x00 0x00 0xaf everywhere) is to use shifts:

unsigned char bytes[4];
unsigned long n = 175;

bytes[0] = (n >> 24) & 0xFF;
bytes[1] = (n >> 16) & 0xFF;
bytes[2] = (n >> 8) & 0xFF;
bytes[3] = n & 0xFF;

The methods using unions and memcpy() will get a different result on different machines.


The issue you are having is with the printing rather than the conversion. I presume you are using char rather than unsigned char, and you are using a line like this to print it:

printf("%x %x %x %x\n", bytes[0], bytes[1], bytes[2], bytes[3]);

When any types narrower than int are passed to printf, they are promoted to int (or unsigned int, if int cannot hold all the values of the original type). If char is signed on your platform, then 0xff likely does not fit into the range of that type, and it is being set to -1 instead (which has the representation 0xff on a 2s-complement machine).

-1 is promoted to an int, and has the representation 0xffffffff as an int on your machine, and that is what you see.

Your solution is to either actually use unsigned char, or else cast to unsigned char in the printf statement:

printf("%x %x %x %x\n", (unsigned char)bytes[0],
                        (unsigned char)bytes[1],
                        (unsigned char)bytes[2],
                        (unsigned char)bytes[3]);
betabandido
  • 18,946
  • 11
  • 62
  • 76
caf
  • 233,326
  • 40
  • 323
  • 462
  • Edited my question so you can see the issue I am having with your solution. – Jacob Nelson Sep 24 '10 at 05:57
  • 2
    @jacobnlsn: It's a problem with the way you're printing it, see update. – caf Sep 24 '10 at 06:14
  • Could you explain the '& 0xFF;' a little bit please? What does this code do? – ZerOne Sep 06 '16 at 09:00
  • 2
    ZerOne: `&` is bitwise-AND, which gives a result where each bit is 1 iff the corresponding bits in both operands are 1. `a & 0xFF` then gives a result where the lowest 8 bits are the same as the lowest 8 bits in `a`, and the remaining bits are all zero. – caf Sep 06 '16 at 11:56
  • In this case, is applying 0xFF mask useful? Unsigned long to unsigned char conversion only keeps rightmost byte – rem Oct 16 '17 at 22:11
  • 4
    @rem: Although uncommon, `char` is allowed to be wider than 8 bits (some DSP programming environments exhibit this) so the mask just ensures the right thing happens in that case. For the common case, it'll be optimised out anyway. – caf Oct 17 '17 at 05:34
  • @caf the problem with your method is that number becomes a char array ,so you cannot do mathematical operation on it – naumaan Mar 24 '21 at 18:47
  • 1
    @user143252: That's exactly what the original question asked for, though. – caf Mar 29 '21 at 00:04
  • @caf by doing this way it remains an integer https://github.com/SyedSajjadHaider/C_Programs/blob/master/little_endian_to_big_conversion32bit.c – naumaan Mar 29 '21 at 09:07
  • 1
    @user143252: Sure, but that's not what the person asking this question wanted. – caf Mar 30 '21 at 13:31
18

Do you want to address the individual bytes of a 32-bit int? One possible method is a union:

union
{
    unsigned int integer;
    unsigned char byte[4];
} foo;

int main()
{
    foo.integer = 123456789;
    printf("%u %u %u %u\n", foo.byte[3], foo.byte[2], foo.byte[1], foo.byte[0]);
}

Note: corrected the printf to reflect unsigned values.

Blastfurnace
  • 18,411
  • 56
  • 55
  • 70
7

In your question, you stated that you want to convert a user input of 175 to 00000000 00000000 00000000 10101111, which is big endian byte ordering, also known as network byte order.

A mostly portable way to convert your unsigned integer to a big endian unsigned char array, as you suggested from that "175" example you gave, would be to use C's htonl() function (defined in the header <arpa/inet.h> on Linux systems) to convert your unsigned int to big endian byte order, then use memcpy() (defined in the header <string.h> for C, <cstring> for C++) to copy the bytes into your char (or unsigned char) array.

The htonl() function takes in an unsigned 32-bit integer as an argument (in contrast to htons(), which takes in an unsigned 16-bit integer) and converts it to network byte order from the host byte order (hence the acronym, Host TO Network Long, versus Host TO Network Short for htons), returning the result as an unsigned 32-bit integer. The purpose of this family of functions is to ensure that all network communications occur in big endian byte order, so that all machines can communicate with each other over a socket without byte order issues. (As an aside, for big-endian machines, the htonl(), htons(), ntohl() and ntohs() functions are generally compiled to just be a 'no op', because the bytes do not need to be flipped around before they are sent over or received from a socket since they're already in the proper byte order)

Here's the code:

#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>

int main() {
    unsigned int number = 175;

    unsigned int number2 = htonl(number);
    char numberStr[4];
    memcpy(numberStr, &number2, 4);

    printf("%x %x %x %x\n", numberStr[0], numberStr[1], numberStr[2], numberStr[3]);

    return 0;
}

Note that, as caf said, you have to print the characters as unsigned characters using printf's %x format specifier.

The above code prints 0 0 0 af on my machine (an x86_64 machine, which uses little endian byte ordering), which is hex for 175.

villapx
  • 1,743
  • 1
  • 15
  • 31
1

Why would you need an intermediate cast to void * in C++ Because cpp doesn't allow direct conversion between pointers, you need to use reinterpret_cast or casting to void* does the thing.

Luiz Felipe
  • 1,123
  • 8
  • 14
1

You can try:

void CopyInt(int value, char* buffer) {
  memcpy(buffer, (void*)value, sizeof(int));
}
jbernadas
  • 2,540
  • 18
  • 12
  • 3
    You shouldn't use `char` for bytes, use `uint8_t`. `(void*)value` is plain wrong, should be `&value`. – Lundin Mar 13 '19 at 13:46
0
int a = 1;
char * c = (char*)(&a); //In C++ should be intermediate cst to void*
gandjustas
  • 1,925
  • 14
  • 12
0

You can simply use memcpy as follows:

unsigned int value = 255;
char bytes[4] = {0, 0, 0, 0};
memcpy(bytes, &value, 4);
pushkin
  • 9,575
  • 15
  • 51
  • 95
HomDhi
  • 31
  • 1
-1

The issue with the conversion (the reason it's giving you a ffffff at the end) is because your hex integer (that you are using the & binary operator with) is interpreted as being signed. Cast it to an unsigned integer, and you'll be fine.

Enusi
  • 101
  • 1
  • 5
-1

An int is equivalent to uint32_t and char to uint8_t.

I'll show how I resolved client-server communication, sending the actual time (4 bytes, formatted in Unix epoch) in a 1-bit array, and then re-built it in the other side. (Note: the protocol was to send 1024 bytes)

  • Client side

    uint8_t message[1024];
    uint32_t t = time(NULL);
    
    uint8_t watch[4] = { t & 255, (t >> 8) & 255, (t >> 16) & 255, (t >> 
    24) & 255 };
    
    message[0] = watch[0];
    message[1] = watch[1];
    message[2] = watch[2];
    message[3] = watch[3];
    send(socket, message, 1024, 0);
    
  • Server side

    uint8_t res[1024];
    uint32_t date;
    
    recv(socket, res, 1024, 0);
    
    date = res[0] + (res[1] << 8) + (res[2] << 16) + (res[3] << 24);
    
    printf("Received message from client %d sent at %d\n", socket, date);
    

Hope it helps.

-2

The problem is arising as unsigned char is a 4 byte number not a 1 byte number as many think, so change it to

union {
unsigned int integer;
char byte[4];
} temp32bitint;

and cast while printing, to prevent promoting to 'int' (which C does by default)

printf("%u, %u \n", (unsigned char)Buffer[0], (unsigned char)Buffer[1]);
Dr. Sahib
  • 156
  • 10