将n字节整数拆分为单个字节的便携式方式

5
问题很简单:将32位或64位整数分割成若干字节发送到1字节接口(通常是uart、spi或i2c)上。我可以使用位掩码和移位轻松获取所需内容,但我希望这个方法具有可移植性,可以在大端和小端上工作,并且适用于不舍弃位但通过进位旋转的平台(掩码会去除多余位吗?)。以下是示例代码:
uint32_t value;
uint8_t buffer[4];
buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;

我希望能够保证这在任何支持32位整数或更高的平台上都能正常运行。我不知道这是否正确。

7
移位和掩码在不同字节序下均可使用。 - Weather Vane
代码很好,可以在现代机器上移植。关于“使其适用于不丢弃位而是像循环缓冲区一样滚动到另一侧”的平台,这个表述不够清晰,请进一步解释这个问题。 - chux - Reinstate Monica
>> 运算符始终是位移,而不是旋转(即它总是丢弃右侧的位)。 - interjay
决定 C 代码行为的不是机器码,而是相反。在 C 中,无符号移位保证表现为逻辑移位,而不管 CPU 支持哪些指令。生成的机器码可能是 ROR 指令,但进位则被丢弃。唯一的例外是对负数进行有符号右移,C 不指定会发生什么 - 编译器可以自由选择使用逻辑移位或算术移位。 - Lundin
你也可以尝试使用联合体,类似于 union { uint32_t u32; uint8_t u8[4]; } t; t.u32 = value; 这样的代码。 - Giovanni Cerretani
显示剩余2条评论
1个回答

7
你提供的代码是最便携的方法。你将一个32位宽度的无符号整数值转换为一个8位宽度的无符号整数值数组。在buffer数组中得到的字节按大端序排列。
掩码不是必需的。从C11 6.5.7p5可以看出:

E1 >> E2的结果是E1向右移动E2个位位置。如果E1具有无符号类型或如果E1具有带符号类型和非负值,则结果的值是E1 / 2 ^ E2的商的整数部分。

将其转换为8位宽度的整数等于掩码8位的值。因此,(result > > 24) & 0xff等于(uint8_t)(result > > 24)(对于该值)。由于你将其分配给uint8_t变量,所以掩码不是必需的。无论如何,我会安全地假设它会被合理的编译器优化掉。
我建议查看一个我记得的实现,我猜它已经以一种非常安全的方式实现了从字节到固定宽度整数的所有可能的拆分和组合变体,包括64位,并返回,即在gpsd bits.h

1
屏蔽通常用于消除编译器/静态分析器警告。例如,MISRA-C检查器甚至要求您使用(uint8_t)(value >> 24)并进行显式转换。 - Lundin
MISRA 应被视为一种独立的不同语言 :)。 - 0___________

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