我对使用Arduino IDE 1.8.2(gcc 4.9.2。)隐式转换uint8_t
和uint16_t
有疑问。硬件是标准的Arduino(ATMega328p)。
我使用uint8_t
编写了一段代码,然后决定切换到uint16_t
。 (应该看到即将来临......)
但是,对于隐式转换,它们的行为似乎略有不同,这是导致程序出错的原因。
最低工作示例如下:
void setup()
{
uint8_t x = 15;
uint8_t y = 5;
float myF = y-x;
Serial.begin(74880);
Serial.println(myF);
}
这将在我的串行控制台上打印-10.00 那很好,我的期望。
但是,如果我将x
(或x
和y
)更改为uint16_t
,结果将为65526.00!
如果我将myF
从float更改为int,我再次得到-10。 (我永远不会改变任何值)
当我将结果存储在有符号数据类型中时,我假设编译器意识到负值的可能性并且"正确处理情况" (保留符号,就像在int情况下一样)或打印警告,以防它对数据类型不匹配感到高兴。但是,即使将警告级别设置为" all"它从未出现过警告。所以我假设编译器知道如何在不丢失符号/数据的情况下处理这种情况。
此外,因为它使用int作为目标数据类型,所以我很惊讶它不适用于更大的浮点数。
我已经在我的x86系统上测试了这种情况 - gcc 4.7.3保留了这个标志。但是,在AVR的8位微控制器世界中,可能适用不同的规则/条件。 (?)
那是怎么回事?也许拥有更多编译器知识的人可以在这里帮忙..
(我知道我可以通过明确的施法避免这种情况,但因此我必须意识到这个陷阱
所以我想知道究竟是什么原因引起的,因为从uint8_t
切换到uint16_t
时真的很惊讶。)
我已经读过根据integer conversion rules"小于int的整数类型在对它们执行操作时被提升为int"。我假设avr-gcc遵循整数提升。 (?)所以我理解实际计算通常在int上运行,然后转换为目标数据类型(在这种情况下为float)。这里的问题是uint16_t
是否与AVR的16位int相等但不小,因此无法提升uint16_t
?如果是这样,为什么它使用int作为目标类型?
为什么它可以作为目标变量使用int,但不能使用4字节的浮点数? 为什么不警告?
答案 0 :(得分:4)
那么那里发生了什么?
如果
int
可以表示原始类型的所有值...,则该值将转换为int
;否则,它将转换为unsigned int
。这些被称为整数促销 C11§6.3.1.12
使用以下内容,y-x
会将每个x,y
提升为int
并计算5-15,即int -10
并将该值分配给mF
。
uint8_t x = 15;
uint8_t y = 5;
float myF = y-x;
使用以下内容,y-x
会将每个x,y
提升为unsigned
并计算5u-15u unsigned 65526u
并将该值分配给mF
。
uint16_t x = 15;
uint16_t y = 5;
float myF = y-x;
为什么unsigned
而不是int
?在宣传uint16_t
时,int
不符合“如果int
可以代表16位uint16_t
平台上的所有原始类型值”条件。
在具有16位int/unsigned
答案 1 :(得分:1)
你是使用无符号整数去负将这些无符号类型转换为float,这是 undefined 实现定义的行为。使用int8_t或int16_t正确处理负值。从uint16_t浮动的转换与uint8_t的转换相比,行为的差异取决于实现,因此很难确切知道发生了什么。