将 int 转换为4字节的 char 数组(C)

嘿,我想把用户输入的 int 转换成4个字节,分配给一个字符数组。这怎么可能呢?

例如:

将用户输入175转换为

00000000 00000000 00000000 10101111


问题与所有的答案到目前为止,转换255应该导致 0 0 0 ff,虽然它打印出来为: 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];

两者都导致 0 0 0 ffffffff而不是 0 0 0 ff

另一个例子是175,输入输出为 0, 0, 0, ffffffaf,而它应该只是 0, 0, 0, af

242028 次浏览
int a = 1;
char * c = (char*)(&a); //In C++ should be intermediate cst to void*

You can try:

void CopyInt(int value, char* buffer) {
memcpy(buffer, (void*)value, sizeof(int));
}

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.

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]);

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.

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]);

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.

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.

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.

You can simply use memcpy as follows:

unsigned int value = 255;
char bytes[4] = {0, 0, 0, 0};
memcpy(bytes, &value, 4);