使用 avr-gcc 隐式转换为 float:uint8_t 与 uint16_t
Implicit conversion to float using avr-gcc: uint8_t vs. uint16_t
我有一个关于使用 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。 (我从不更改任何值)
当我将结果存储在带符号的数据类型中时,我假设编译器意识到负值和 "handles the situation correctly" 的可能性(保留符号,就像在 int 情况下一样)或在中打印警告如果它对不匹配的数据类型不满意。但是,即使将警告级别设置为 "all",它也从未显示警告。所以我假设编译器知道如何在不丢失 sign/data.
的情况下处理这种情况
此外,由于它使用 int 作为目标数据类型,令我惊讶的是它不适用于更大的浮点数。
我已经在我的x86 系统上测试了这种情况- gcc 4.7.3 保留了标志。然而,在 AVR 的 8 位微控制器世界中,不同的 rules/conditions 可能适用。 (?)
那么那里发生了什么?也许具有更多编译器知识的人可以在这里提供帮助..
(我知道我可以通过显式转换来避免这种情况,但因此我必须意识到这个陷阱。
所以我想知道到底是什么原因造成的,因为当从 uint8_t
切换到 uint16_t
时真的很惊喜..)
我已经根据 integer conversion rules "integer types smaller than int are promoted to int when an operation is performed on them" 阅读了该内容。我假设 avr-gcc 遵循整数提升。 (?) 所以我知道实际计算通常在 int 上运行,然后转换为目标数据类型(在本例中为 float)。这里的问题是 uint16_t
与 AVR 的 16 位 int 相等但大小不小,因此无法提升 uint16_t
吗?如果是这样,为什么它使用 int 作为目标类型?
为什么它使用 int 作为目标变量,而不是 4 字节浮点数?
为什么它不发出警告?
您使用无符号整数变为负值将这些无符号类型转换为浮点数,这是未定义实现定义的行为。使用 int8_t 或 int16_t 来正确处理负值。从 uint16_t 转换为浮动与从 uint8_t 转换的行为差异取决于实现,因此很难准确判断发生了什么。
So what is going on there?
整数促销
If an int
can represent all values of the original type ..., the value is converted to an int
; otherwise, it is converted to an unsigned int
. These are called the integer promotions.
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
并计算 5u-15u 即 unsigned 65526u
并将该值分配给 mF
。
uint16_t x = 15;
uint16_t y = 5;
float myF = y-x;
为什么是 unsigned
而不是 int
? uint16_t
在 16 位 int
平台上升级 uint16_t
时不满足“如果 int
可以表示原始类型的所有值”条件。
没什么神秘的,只是 整数促销 在具有 16 位 int/unsigned
的平台上
我有一个关于使用 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。 (我从不更改任何值)
当我将结果存储在带符号的数据类型中时,我假设编译器意识到负值和 "handles the situation correctly" 的可能性(保留符号,就像在 int 情况下一样)或在中打印警告如果它对不匹配的数据类型不满意。但是,即使将警告级别设置为 "all",它也从未显示警告。所以我假设编译器知道如何在不丢失 sign/data.
的情况下处理这种情况此外,由于它使用 int 作为目标数据类型,令我惊讶的是它不适用于更大的浮点数。
我已经在我的x86 系统上测试了这种情况- gcc 4.7.3 保留了标志。然而,在 AVR 的 8 位微控制器世界中,不同的 rules/conditions 可能适用。 (?)
那么那里发生了什么?也许具有更多编译器知识的人可以在这里提供帮助..
(我知道我可以通过显式转换来避免这种情况,但因此我必须意识到这个陷阱。
所以我想知道到底是什么原因造成的,因为当从 uint8_t
切换到 uint16_t
时真的很惊喜..)
我已经根据 integer conversion rules "integer types smaller than int are promoted to int when an operation is performed on them" 阅读了该内容。我假设 avr-gcc 遵循整数提升。 (?) 所以我知道实际计算通常在 int 上运行,然后转换为目标数据类型(在本例中为 float)。这里的问题是 uint16_t
与 AVR 的 16 位 int 相等但大小不小,因此无法提升 uint16_t
吗?如果是这样,为什么它使用 int 作为目标类型?
为什么它使用 int 作为目标变量,而不是 4 字节浮点数? 为什么它不发出警告?
您使用无符号整数变为负值将这些无符号类型转换为浮点数,这是未定义实现定义的行为。使用 int8_t 或 int16_t 来正确处理负值。从 uint16_t 转换为浮动与从 uint8_t 转换的行为差异取决于实现,因此很难准确判断发生了什么。
So what is going on there?
整数促销
If an
int
can represent all values of the original type ..., the value is converted to anint
; otherwise, it is converted to anunsigned int
. These are called the integer promotions.
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
并计算 5u-15u 即 unsigned 65526u
并将该值分配给 mF
。
uint16_t x = 15;
uint16_t y = 5;
float myF = y-x;
为什么是 unsigned
而不是 int
? uint16_t
在 16 位 int
平台上升级 uint16_t
时不满足“如果 int
可以表示原始类型的所有值”条件。
没什么神秘的,只是 整数促销 在具有 16 位 int/unsigned