在C语言中将4字节的字符转换为int32

20

我先将一个int32数字转换为char [4]数组,然后通过(int *)将数组转换回int32,但是数字与之前不同:

unsigned int num = 2130706432;
unsigned int x;
unsigned char a[4];

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

x = *(int *)a;
printf("%d\n", x);

输出结果为127。如果我将num设置为127,则输出结果为2130706432。有人有想法吗?


7
你的平台是小端序还是大端序?链接(http://en.wikipedia.org/wiki/Endianness)。在你的平台上,int类型的字节顺序可能和你想象的不一样。 - Eric J.
2
@zwx:我认为x = *(int *)a;违反了严格别名规则(启用警告后尝试编译),在现代C中,您应该使用联合来进行类型转换(但最好通过位移来完成)。请参见http://stackoverflow.com/questions/8143857/bad-value-affectation-after-type-casting/8159802#8159802。 - ninjalj
3
@ninjalj: 没错。这段代码实际上是UB(未定义行为)。正确的做法是反转顺序:unsigned int x; unsigned char * a = (unsigned char*)(&x); - Kerrek SB
@BenVoigt:在C99中,这不是未定义行为:https://dev59.com/NWoy5IYBdhLWcg3wfeMR - ninjalj
啊,对了,我之前的评论是基于C++规则的。抱歉。(虽然C确实有这样的规则,但正如@ninjalj链接中提到的答案所述,它被指定为一个缺陷) - Ben Voigt
显示剩余3条评论
4个回答

18

将a[]数组的索引顺序颠倒,例如 a[0] -> a[3]

我认为你的字节序反了。

尝试这样做:

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

10

要查看发生了什么,请使用

printf("%x\n", ...);

打印输入和输出数字。

与大小端无关的方式:

x = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];

1
我不知道为什么这个被投票赞成了。如果它是一种与字节序无关的方式,那么它应该在我的电脑上也能工作。但我必须做相反的操作 uint32_t var2 = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0]; - rightaway717
2
我使用 vector<unsigned char> ,并使用 memcpy 将其填充为 uint32_t 变量: memcpy(&v[0], &var, sizeof var); - rightaway717
1
@rightaway717 所以请将其保存在您计算机的字节序中。如果要以字节序无关的方式进行操作,则必须像 OP 一样将 uint32_t 转换为数组,然后像我一样将数组转换为 uint32_t。 - Adam Trhon

6
这一行在小端机器上永远不会正常工作:
x = *(int *)a;

在打印出值之前,您需要解压数据。


此外,在利用严格别名规则的编译器上,它可能无法在大端机器上运行。 - ninjalj

5
您的代码 a[0] = (num>>24) & 0xFF;num中取出最高的8位,并将其存储在a的第一个字节中。在小端机器上,第一个字节保存的是最不重要的位。也就是说,在小端机器上,这段代码会取出最高的8位并存储在最不重要位所在的位置,从而改变数值。

2130706432的十六进制表示为0x7F000000,127的十六进制表示为0x0000007F。

此外,x = *(int *)a;会导致未定义的行为。考虑硬件情况,如果从未正确对齐的地址读取int会导致总线错误。如果a没有适当地对齐int,那么程序将崩溃。

将字节解释为int的正确方法是std::memcpy(&x, a, sizeof x);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接