我在嵌入式系统上有一些代码。代码可以在link看到,特别是此代码段:
uint32_t raw_fusebits[2];
....
/* Read the fuse settings in the user row, 64 bit */
((uint16_t*)&raw_fusebits)[0] = (uint16_t)NVM_MEMORY[NVMCTRL_USER / 2];
((uint16_t*)&raw_fusebits)[1] = (uint16_t)NVM_MEMORY[(NVMCTRL_USER / 2) + 1];
((uint16_t*)&raw_fusebits)[2] = (uint16_t)NVM_MEMORY[(NVMCTRL_USER / 2) + 2];
((uint16_t*)&raw_fusebits)[3] = (uint16_t)NVM_MEMORY[(NVMCTRL_USER / 2) + 3];
这会导致C99下的编译器警告与严格别名相关。有没有更好的方法来写这个?起初我想(使用一些更简单的变量名来提高可读性):
uint32_t x[2];
uint16_t a, b, c, d;
x[0] = ((uint32_t)a << 16) | ((uint32_t)b);
x[1] = ((uint32_t)c << 16) | ((uint32_t)d);
然后我转到了,
x[0] = ((uint32_t)b << 16) | ((uint32_t)a);
x[1] = ((uint32_t)d << 16) | ((uint32_t)c);
哪个是正确的但是在我的小端机器上。然后我想知道为什么当我用某些值测试这些时,字节顺序并不适用。
是否有一种编译器友好的方式来重写库代码以使其与endian无关?
编辑:在第73行,您可以看到NVM_MEMORY的定义,因此大小至少是一致的。
#define NVM_MEMORY ((volatile uint16_t *)FLASH_ADDR)
答案 0 :(得分:1)
这个怎么样?
memcpy(raw_fusebits, NVM_MEMORY + (NVMCTRL_USER / 2), sizeof(raw_fusebits));
假设字段按原样复制,一次16位,原始代码中似乎没有任何字节顺序处理。使用memcpy()
可以避免严格别名问题。
答案 1 :(得分:1)
在这种情况下,您可以按照John的建议使用memcpy
。但是,如果计算了您需要分配的值,memcpy
将是不够的。在这种情况下,编译器友好的方法来为C支持的别名值使用union
:
union {
struct {
uint32_t val[2];
} u32;
struct {
uint16_t val[4];
} u16;
} raw;
...
raw.u16.val[0] = NVM_MEMORY[NVMCTRL_USER / 2];
raw.u16.val[1] = NVM_MEMORY[(NVMCTRL_USER / 2) + 1];
raw.u16.val[2] = NVM_MEMORY[(NVMCTRL_USER / 2) + 2];
raw.u16.val[3] = NVM_MEMORY[(NVMCTRL_USER / 2) + 3];
/* obtain 32-bit values from raw.u32.val[0] and raw.u32.val[1] */