使用avr-gcc隐式转换为浮点数:uint8_t与uint16_t

时间:2018-06-13 16:43:35

标签: c++ arduino floating-point type-conversion avr-gcc

我对使用Arduino IDE 1.8.2(gcc 4.9.2。)隐式转换uint8_tuint16_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(或xy)更改为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字节的浮点数? 为什么不警告?

2 个答案:

答案 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的转换相比,行为的差异取决于实现,因此很难确切知道发生了什么。