我有一个关于使用 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
从浮点数更改为 int,我会再次得到 -10。(我从不更改任何值(
当我将结果存储在有符号数据类型中时,我假设编译器意识到负值的可能性并"正确处理情况"(保留符号,就像在 int 情况下一样(或打印警告以防它对不匹配的数据类型不满意。但是,即使将警告级别设置为"全部",它也从未显示警告。所以我假设编译器知道如何在不丢失符号/数据的情况下处理这种情况。
此外,由于它适用于 int 作为目标数据类型,因此令我惊讶的是它不适用于更大的浮点数。
我已经在我的 x86 系统上测试了这种情况 - gcc 4.7.3 保留了标志。但是,在 AVR 的 8 位微控制器领域,可能适用不同的规则/条件。(?)
这到底是怎么回事呢?也许有更多编译器知识的人可以在这里提供帮助。
(我知道我可以通过显式投射来避免这种情况,但因此我必须意识到这个陷阱。
所以我想知道究竟是什么原因造成的,因为从uint8_t
切换到uint16_t
时确实是一个惊喜......
我读过,根据整数转换规则,"当对它们执行操作时,小于 int 的整数类型将提升为 int"。我假设 avr-gcc 遵循整数促销。(?)所以我知道实际计算通常无论如何都在 int 上运行,然后转换为目标数据类型(在这种情况下为 float(。这里的问题是uint16_t
等于,但不小于 AVR 的 16 位 int,因此无法提升uint16_t
?如果是这样,为什么它使用 int 作为目标类型?
为什么它使用 int 作为目标变量,而不是 4 字节浮点数? 为什么它不警告?
那么这是怎么回事呢?
整数促销
如果一个
int
可以表示原始类型的所有值...,则该值将转换为int
;否则,它将转换为unsigned int
。这些称为整数促销.
C11 §6.3.1.1 2
通过以下内容,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
并计算unsigned 65526u
的 5u-15u 并将该值分配给mF
。
uint16_t x = 15;
uint16_t y = 5;
float myF = y-x;
为什么unsigned
而不是int
? 升级uint16_t
时,uint16_t
不满足 16 位int
平台上的"如果int
可以表示原始类型的所有值"条件。
没有神秘感,只是在具有 16 位int/unsigned
的平台上进行整数促销
你