将一个UINT32值转换为UINT8数组[4]

21

我的问题是如何将一个UINT32值转换为一个UINT8数组[4](使用C/C++),最好不依赖于字节序的方式?此外,如何从UINT8数组[4]重构UINT32值,以便回到起点?


1
你想如何进行转换?大端还是小端?具体来说:如果你的输入是0x12345678,你想让数组[0]是0x12还是0x78?这个需要你自己决定。然后我们才能帮助你。 - TonyK
5个回答

40

你并没有明确说明通过独立于字节序实现什么 - 因为字节数组必须具有某种字节序,所以这是不清楚的。即便如此,以下其中之一必定能够满足您的要求:

给定UINT32 vUINT8 a[4]

"主机"字节序

(使用计算机的本机字节序):

UINT8 *vp = (UINT8 *)&v;
a[0] = vp[0];
a[1] = vp[1];
a[2] = vp[2];
a[3] = vp[3];

或者:

memcpy(a, &v, sizeof(v));

或者:

*(UINT32 *)a = v;

大端模式

(又称为“网络序”):

a[0] = v >> 24;
a[1] = v >> 16;
a[2] = v >>  8;
a[3] = v;

小端序

a[0] = v;
a[1] = v >>  8;
a[2] = v >> 16;
a[3] = v >> 24;

你有移动语义的解决方案吗?假设你想将v的值移动到字节数组中,而不是复制v。 - jiggunjer
1
@jiggunjer,那没有意义。原始值不能像那样“移动”。 - Alnitak
1
@jiggunjer 是的。如果你在谈论C++11中的“移动语义”,那么在32位变量中没有什么可以“移动”的。 - Alnitak
1
我意识到这是一个旧答案(它被EE.SE的一个问题所喜欢)。但是*(UINT32 *)a = v;是一个非常危险的假设 - 如果a没有初始化对齐到UINT32字边界,这很可能会导致未对齐访问错误。 - Tom Carpenter

15

例如,像这样:

UINT32 value;
UINT8 result[4];

result[0] = (value & 0x000000ff);
result[1] = (value & 0x0000ff00) >> 8;
result[2] = (value & 0x00ff0000) >> 16;
result[3] = (value & 0xff000000) >> 24;

编辑:添加括号(>> 的优先级似乎高于&)


2
@R.:我不同意。它们表达了对称性(我通常为此目的使用 >> 0),而且必须是一个非常糟糕的编译器才不能将它们优化掉。 - Oliver Charlesworth
4
无论&运算符在美学上有多少价值,事实是它们会导致代码难以理解。>>的优先级高于& - TonyK
1
@R.:实际上,我撤回我的话。我忽略了我们正在转换为uint8的事实,所以所有掩码都是不必要的,正如@Stephen指出的那样。 - Oliver Charlesworth
4
关于使用 & 符号:你编写代码不仅是为了编译器,也是为了在你之后读取代码的人。在我看来,添加 & 可以清楚地表明你正在处理特定的字节,而不依赖于任何背后被截断的内容。我认为编译器比代码读者更聪明。因此,不要让代码易读给编译器,而是应该易读给读者。 - Patrick
2
你应该注意这是小端序。 - Albert
显示剩余4条评论

3
如果您不想自己编写代码,可以使用C库函数htonl()将32位整数转换为网络字节顺序。还有一个函数ntohl()可将其转换回主机字节顺序。
一旦它们处于网络字节顺序,只需将int / long作为字节数组访问即可。
总的来说,这可能是实现您目标最具可移植性和经过测试的方法。

1

也可以使用指针来完成。 (这是小端序,但如果您使用相同的重构方法,它不会有影响)

uint32 in = 0x12345678;
uint8 out[4];
*(uint32*)&out = in;

这将把uint32的值分配给uint8内存地址之后的4个字节,正好满足您的需求。
要反过来:
uint8 in[4] = {0x78, 0x56, 0x34, 0x12};
uint32 out;
out = *(uint32*)&in

1
我意识到这是一个旧答案(它被EE.SE的一个问题所链接)。但是*(uint32*)&out = in;是一个非常危险的假设 - 如果a没有初始化对齐到uint32字边界,这可能会导致某些处理器上的未对齐访问错误。 - Tom Carpenter

-4

使用由一个包含4个uint8类型的数组和一个uint32类型组成的联合体。

这样它就会自动按照c语言内在指针魔法进行排序(数组是指向数组开头的指针)。


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