我想使用uint32_t
存储4个独立的uint8_t
值,并且能够单独读取/写入每个值。
是否可以安全地执行以下任一操作来设置每个8位范围的值,如果是,哪个更好(更快,更便携)?我不一定试图一次性设置它们,我只是说明如何在任何时间点设置每个8位值。
uint32_t x = ...;
选项1:
((uint8_t *)(&x))[0] = a;
((uint8_t *)(&x))[1] = b;
((uint8_t *)(&x))[2] = c;
((uint8_t *)(&x))[3] = d;
选项2:
x = (x & 0xFFFFFF00) | (uint32_t) a;
x = (x & 0xFFFF00FF) | (uint32_t) b << 8;
x = (x & 0xFF00FFFF) | (uint32_t) c << 16;
x = (x & 0x00FFFFFF) | (uint32_t) d << 24;
您的初始修订版本是正确的 尽管是回旋处 选项2的方法,即
// a, b, c, and d are of initialized and of type uint8_t
uint32_t x = ...;
x = (x & 0xFFFFFF00) | (uint32_t) a;
x = (x & 0xFFFF00FF) | (uint32_t) b << 8;
x = (x & 0xFF00FFFF) | (uint32_t) c << 16;
x = (x & 0x00FFFFFF) | (uint32_t) d << 24;
选项2的此修订版错误:
uint32_t x = ...;
x |= (uint32_t) a;
x |= (uint32_t) b << 8;
x |= (uint32_t) c << 16;
x |= (uint32_t) d << 24;
即使x
被初始化,它仍然是错误的,因为你没有设置8位范围,你正在对它们进行ORing。
正确的方法是
// a, b, c, and d are of initialized and of type uint8_t
uint32_t x = (uint32_t) a;
x |= (uint32_t) b << 8;
x |= (uint32_t) c << 16;
x |= (uint32_t) d << 24;
或者更简洁
// a, b, c, and d are of initialized and of type uint8_t
uint32_t x =
(uint32_t) a
| (uint32_t) b << 8
| (uint32_t) c << 16
| (uint32_t) d << 24;
选项1的问题在于它假定uint32_t
的字节序首先是LSB,因此不是便携式解决方案。
在收到有关您提出的问题的说明后,您的初始修订版(本答复中的第一个代码块)是正确的方法。它将剩余的24位保持不变,同时将特定的8位范围设置为RHS上的uint8_t
值。
通用功能(适用于pos8 16和24):
uint32_t setb(uint32_t val, uint8_t a, int pos)
{
val &= ~(0xffUL << pos);
val |= (uint32_t)a << pos;
return val;
}
如果你不喜欢轮班:
uint32_t f(uint8_t a, uint8_t b,uint8_t c,uint8_t d) {
return a + 0x100UL * b + 0x10000UL * c + 0x1000000UL * d;
}
任何好的优化编译器都会生成非常高效的代码
gcc ARM
f:
add r0, r0, r2, lsl #16
add r0, r0, r3, lsl #24
add r0, r0, r1, lsl #8
bx lr
clang x86
f: # @f
shl esi, 8
lea eax, [rsi + rdi]
shl edx, 16
or eax, edx
shl ecx, 24
or eax, ecx
ret
只有在非常小的微观上,我才会推荐工会方式
uint32_t g(uint8_t a, uint8_t b,uint8_t c,uint8_t d)
{
union
{
uint32_t v32;
uint8_t v8[4];
}x = {.v8[0] = a, .v8[1] = b, .v8[2] = c, .v8[3] = d};
return x.v32;
}
因为它更容易优化:
__zero_reg__ = 1
f:
push r16
push r17
ldi r25,lo8(0)
ldi r26,lo8(0)
ldi r27,hi8(0)
add r24,r22
adc r25,__zero_reg__
adc r26,__zero_reg__
adc r27,__zero_reg__
ldi r21,lo8(0)
subi r20,lo8(-(8))
sbci r21,hi8(-(8))
rjmp 2f
1: lsl r24
rol r25
rol r26
rol r27
2: dec r20
brpl 1b
ldi r19,lo8(0)
subi r18,lo8(-(16))
sbci r19,hi8(-(16))
rjmp 2f
1: lsl r24
rol r25
rol r26
rol r27
2: dec r18
brpl 1b
mov r19,r24
clr r18
clr r17
clr r16
mov r22,r16
mov r23,r17
mov r24,r18
mov r25,r19
pop r17
pop r16
ret
g:
push r16
push r17
mov r25,r18
mov r17,r22
mov r22,r24
mov r23,r17
mov r24,r20
pop r17
pop r16
ret