我需要编写一个函数,将指定数量的给定整数的低序字节复制到内存中的地址中,同时保留其顺序。
void lo_bytes(uint8_t *dest, uint8_t no_bytes, uint32_t val)
我希望用法如下:
uint8 dest[3];
lo_bytes(dest, 3, 0x44332211);
// Big-endian: dest = 33 22 11
// Little-endian: dest = 11 22 33
我尝试使用移位memcpy
来实现该功能,并使用for循环遍历val
的每个字节,但是我所有的尝试都无法在任一方法上进行或其他字节序。
是否可以通过独立于平台的方式来执行此操作,还是我需要使用#ifdef
并为每个字节序使用单独的代码?
答案 0 :(得分:2)
我尝试使用移位
memcpy
和 用for循环遍历val
的每个字节,但是我所有的 尝试对一个或另一个字节序都无效。
所有算术,包括按位算术,都是根据操作数的值而不是它们的表示形式定义的。对于您来说这还不够,因为您希望获得的结果因类型uint32_t
的表示样式的细节而异。
您可以通过多种方法对对象表示进行操作,但是您仍然需要知道要对哪些字节进行操作。这需要某种形式的检测。如果您只关心big-endian和little-endian字节顺序,那么我赞成采用类似于@P__J__答案中给出的方法:
void lo_bytes(uint8_t *dest, uint8_t no_bytes, uint32_t val) {
static const union { uint32_t i; uint8_t a[4] } ubytes = { 1 };
memcpy(dest, &val + (1 - ubytes.a[0]) * (4 - no_bytes), no_bytes);
}
如果(1 - ubytes.a[0])
的表示为大端,则表达式uint32_t
的值为1,在这种情况下,高位字节出现在val
的表示的开头。在这种情况下,我们要跳过表示的前4 - no_bytes
并复制其余的。另一方面,如果uint32_t
具有小尾数表示,则(1 - ubytes.a[0])
的值将为0,结果memcpy
从表示的开头开始。在每种情况下,无论从val
的表示形式复制哪个字节,都将保持其顺序。这就是memcpy()
的作用。
答案 1 :(得分:1)
int detect_endianess(void) //1 if little endian 0 if big endianes
{
union
{
uint16_t u16;
uint8_t u8[2];
}val = {.u16 = 0x1122};
return val.u8[0] == 0x22;
}
void lo_bytes(void *dest, uint8_t no_bytes, uint32_t val)
{
if(detect_endianess())
{
memcpy(dest, &val, no_bytes);
}
else
{
memcpy(dest, (uint8_t *)(&val) + sizeof(val) - no_bytes, no_bytes);
}
}
答案 2 :(得分:1)
是否有可能以与平台无关的方式执行此操作,或者我是否需要使用#ifdefs并为每个字节序使用单独的代码?
不,那甚至没有意义。任何关心平台特定特性(例如字节序)的东西都不能独立于平台。
示例1(与平台无关)
// Copy the 3 least significant bytes to dest[]
dest[0] = value & 0xFF; dest[1] = (value >> 8) & 0xFF; dest[2] = (value >> 16) & 0xFF;
示例2(与平台无关)
// Copy the 3 most significant bytes to dest[]
dest[0] = (value >> 8) & 0xFF; dest[1] = (value >> 16) & 0xFF; dest[2] = (value >> 24) & 0xFF;
示例3(取决于平台):
// I want the least significant bytes on some platforms and the most significant bytes on other platforms
#ifdef PLATFORM_TYPE_A
dest[0] = value & 0xFF; dest[1] = (value >> 8) & 0xFF; dest[2] = (value >> 16) & 0xFF;
#endif
#ifdef PLATFORM_TYPE_B
dest[0] = (value >> 8) & 0xFF; dest[1] = (value >> 16) & 0xFF; dest[2] = (value >> 24) & 0xFF;
#endif
请注意,平台依赖性的起因是什么(如果是字节序或其他原因)并没有真正的区别,一旦拥有平台依赖性,就不会具有平台依赖性。