我正在用C语言编写Atmel SAMD20。我遇到了一个错误,我现在已经修复了,但我不确定为什么它首先发生了。有人能指出我吗? (它可能太明显了,我以后会去看脸。)
一组传感器正在生成uint16_t
数据,我将其转换为uint8_t
以通过I2C发送。所以,这就是我最初的写作方式:
for (i = 0; i < SENSBUS1_COUNT; ++i)
{
write_buffer[ (i*2) ] = (uint8_t) sample_sensbus1[i] & 0xff;
write_buffer[(i*2)+1] = (uint8_t) sample_sensbus1[i] >> 8;
}
此处write_buffer
为uint8_t
,sample_sensbus1
为uint16_t
。
由于某种原因,这最终弄乱了最重要的字节(在大多数情况下,最重要的字节只是1(即0x100))。另一方面,这工作正常,而且应该是它应该是:
for (i = 0; i < SENSBUS1_COUNT; ++i)
{
write_buffer[ (i*2) ] = sample_sensbus1[i] & 0xff;
write_buffer[(i*2)+1] = sample_sensbus1[i] >> 8;
}
显然,隐性演员比我聪明。
发生了什么事?
答案 0 :(得分:4)
write_buffer[(i*2)+1] = ((uint8_t) sample_sensbus1[i]) >> 8;
这相当于:
write_buffer[(i*2)+1] = (uint8_t) (sample_sensbus1[i] >> 8);
如你所见,它会在转变之前进行演员表演。你最重要的字节现在消失了。
但这应该有效:
<=
答案 1 :(得分:4)
您的演员阵容会在转换或掩码之前将uint16_t
转换为uint8_t
。它被视为你写道:
write_buffer[ (i*2) ] = ((uint8_t)sample_sensbus1[i]) & 0xff;
write_buffer[(i*2)+1] = ((uint8_t)sample_sensbus1[i]) >> 8;
您可能需要:
write_buffer[ (i*2) ] = (uint8_t)(sample_sensbus1[i] & 0xff);
write_buffer[(i*2)+1] = (uint8_t)(sample_sensbus1[i] >> 8);
在实践中,uncast版本也可以。请记住,演员告诉编译器“我比你知道更多关于这件事的事情;按照我说的去做”。如果您不了解编译器,那将是危险的。尽可能避免施放。
您可能还会注意到,按位(或更多)移动(左或右)类型的大小是未定义的行为。但是,((uint8_t)sample_sensbus[i]) >> 8
不是未定义的行为,因为“通常的算术转换”意味着(uint8_t)sample_sensbus[i]
的结果在转换发生之前转换为int
,并且大小为int
不能是8位(满足标准必须至少为16位),因此移位不会太大。
答案 2 :(得分:3)
这是运营商优先权的问题。在第一个示例中,您首先转换为uint8_t
,然后应用&
和>>
运算符。在第二个示例中,将在隐式转换发生之前应用它们。
答案 3 :(得分:3)
Casting是一元一元的前缀运算符,因此具有很高的优先级。
(uint8_t) sample_sensbus1[i] & 0xff
解析为
((uint8_t)sample_sensbus1[i]) & 0xff
在这种情况下,& 0xff
是多余的。但是:
(uint8_t) sample_sensbus1[i] >> 8
解析为
((uint8_t)sample_sensbus1[i]) >> 8
此处强制转换将数字截断为8位,然后>> 8
将所有内容都移出。
答案 4 :(得分:3)
问题在于这个表达式:
(uint8_t) sample_sensbus1[i] >> 8;
它按以下顺序执行:
sample_sensbus1[i]
转换为uint8_t
,将截断有效地转换为8个最低有效位。这是您丢失数据的地方。 int
作为usual arithmetic conversions的一部分,使得只设置了8个较低位的int。 int
右8
位,有效地使整个表达式为零。