强制转换 (int) 和 (int16_t) 时 C++ 中的含义是什么
what is the meaning in C++ when casting both (int) and (int16_t)
我正在研究 Arduino 示例中用于读取外部数据的 C++ 代码。
该代码使用转换 (int16_t) 和 (int).
int16_t是固定整数类型,但我不明白它在代码中的用途。
_vRaw[0] = (int)(int16_t)(Wire.read() | Wire.read() << 8);
我这样写有什么区别吗?
_vRaw[0] = (int)(Wire.read() | Wire.read() << 8);
(int16_t)
转换会将值截断为 16 位。 (int)
转换什么都不做,除非 _vRaw[0]
有一个类型可以从 int
而不是 int16_t
隐式转换,这是不太可能的。
很可能 Wire.read()
returns char
,并且这些转换都不做任何事情,因为 (Wire.read() | Wire.read() << 8)
已经是一个 int
表达式16位以内。
我以前写过这样的代码,所以我可以向 int16_t
解释转换的目的。
Arduino命令Wire.read()
通常returns一个0到255之间的数字代表从I2C设备读取的一个字节。
有时,您从设备读取的两个字节将使用 Two's complement 表示一个带符号的 16 位数字。因此,例如,如果第一个字节为 1,第二个字节为 2,我们希望将其解释为值 1 + 2*256 = 513。如果两个字节均为 255,我们希望将其解释为 -1。
让我们假设您的代码是为 int
是 32 位的系统(几乎任何 32 位微控制器)编译的,并且两个字节都是 255,并考虑这个表达式:
(Wire.read() | Wire.read() << 8)
这个表达式的值只是 255 | (255 << 8)
,即 65535。这很糟糕;我们希望值为 -1。
修复该错误的简单方法是向 int16_t
添加强制转换:
(int16_t)(Wire.read() | Wire.read() << 8)
当我们将 65535 转换为 int16_t
类型时,我们得到 -1,因为 int16_t
不能容纳 65535(它只能容纳从 -32768 到 32767 的值)。 (C++ 标准不保证我们得到 -1,但它是实现定义的行为,所以如果你想确定,你可以检查 manual of your compiler。)如果我们稍后将它转换回 int
(通过显式转换或通过设置一些 int
等于它),编译器将执行正确的签名扩展操作并给我们一个值为 -1 的 int
。
顺便说一下,我不确定您的编译器是否会 运行 以正确的顺序对 Wire.read()
的两次调用,除非您在这两个调用之间有一个分号。此外,可能不需要最终转换为 int
。所以我会把代码重写成这样:
uint8_t lsb = Wire.read();
_vRaw[0] = (int16_t)(lsb | Wire.read() << 8);
我正在研究 Arduino 示例中用于读取外部数据的 C++ 代码。 该代码使用转换 (int16_t) 和 (int).
int16_t是固定整数类型,但我不明白它在代码中的用途。
_vRaw[0] = (int)(int16_t)(Wire.read() | Wire.read() << 8);
我这样写有什么区别吗?
_vRaw[0] = (int)(Wire.read() | Wire.read() << 8);
(int16_t)
转换会将值截断为 16 位。 (int)
转换什么都不做,除非 _vRaw[0]
有一个类型可以从 int
而不是 int16_t
隐式转换,这是不太可能的。
很可能 Wire.read()
returns char
,并且这些转换都不做任何事情,因为 (Wire.read() | Wire.read() << 8)
已经是一个 int
表达式16位以内。
我以前写过这样的代码,所以我可以向 int16_t
解释转换的目的。
Arduino命令Wire.read()
通常returns一个0到255之间的数字代表从I2C设备读取的一个字节。
有时,您从设备读取的两个字节将使用 Two's complement 表示一个带符号的 16 位数字。因此,例如,如果第一个字节为 1,第二个字节为 2,我们希望将其解释为值 1 + 2*256 = 513。如果两个字节均为 255,我们希望将其解释为 -1。
让我们假设您的代码是为 int
是 32 位的系统(几乎任何 32 位微控制器)编译的,并且两个字节都是 255,并考虑这个表达式:
(Wire.read() | Wire.read() << 8)
这个表达式的值只是 255 | (255 << 8)
,即 65535。这很糟糕;我们希望值为 -1。
修复该错误的简单方法是向 int16_t
添加强制转换:
(int16_t)(Wire.read() | Wire.read() << 8)
当我们将 65535 转换为 int16_t
类型时,我们得到 -1,因为 int16_t
不能容纳 65535(它只能容纳从 -32768 到 32767 的值)。 (C++ 标准不保证我们得到 -1,但它是实现定义的行为,所以如果你想确定,你可以检查 manual of your compiler。)如果我们稍后将它转换回 int
(通过显式转换或通过设置一些 int
等于它),编译器将执行正确的签名扩展操作并给我们一个值为 -1 的 int
。
顺便说一下,我不确定您的编译器是否会 运行 以正确的顺序对 Wire.read()
的两次调用,除非您在这两个调用之间有一个分号。此外,可能不需要最终转换为 int
。所以我会把代码重写成这样:
uint8_t lsb = Wire.read();
_vRaw[0] = (int16_t)(lsb | Wire.read() << 8);