【发布时间】:2018-06-13 16:43:34
【问题描述】:
我有一个关于使用 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 情况下一样)或打印警告以防万一它对不匹配的数据类型不满意。但是,即使将警告级别设置为“全部”,它也不会显示警告。所以我假设编译器知道如何在不丢失符号/数据的情况下处理这种情况。
此外,由于它使用 int 作为目标数据类型,令我惊讶的是它不适用于更大的浮点数。
我已经在我的 x86 系统上测试了这种情况 - gcc 4.7.3 保留了符号。然而,在 AVR 的 8 位微控制器世界中,可能适用不同的规则/条件。 (?)
那么那里发生了什么?也许有更多编译器知识的人可以在这里提供帮助..
(我知道我可以通过显式转换来避免这种情况,但因此我必须意识到这个陷阱。
所以我想知道究竟是什么原因造成的,因为从uint8_t 切换到uint16_t 时确实是一个惊喜......)
根据integer conversion rules“当对它们执行操作时,小于 int 的整数类型被提升为 int”。我假设 avr-gcc 遵循整数促销。 (?)所以我理解实际计算通常在 int 上运行,然后转换为目标数据类型(在这种情况下为浮点数)。这里的问题是uint16_t 与 AVR 的 16 位 int 相同,但大小不小于,因此无法提升 uint16_t?如果是这样,为什么它使用 int 作为目标类型?
为什么它可以使用 int 作为目标变量,但不能使用 4 字节浮点数? 为什么它不发出警告?
【问题讨论】:
-
如果
int是 16 位,那么uint16_t不是“更小”。两个操作数的类型相同,所以减法是用unsigned完成的,并且值以明确定义的方式包装。 -
计算与
float无关,编译器不会“实现”任何东西”。结果分配给float之后。你会有将一个操作数转换为float在计算之前考虑float。 -
(是的,我知道 1 年零 7 个月后)但有趣的是 uint8_t 的 -10 的“预期”结果并不是我所期望的。我会说它应该是 246。预计 65526。而“再次-10”也是预期的结果。由于您从未在其他地方使用过 x 和 y,因此可能已经对其进行了优化。
标签: c++ arduino floating-point type-conversion avr-gcc