带按位或和转换操作数的转换警告
Conversion Warning with Bitwise Or and Casted Operands
代码片段 1(如下所示)产生以下 -Wconversion 警告:
debug_Wconversion.c:10:57: warning: conversion to ‘uint16_t’ from ‘int’ may alter its value [-Wconversion]
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
^
代码片段 2 和 3 不产生 -Wconversion 警告。
代码片段 1:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
代码片段 2:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
uint16_t leftOrOperand;
uint16_t rightOrOperand;
leftOrOperand = ((uint16_t) (((uint16_t) byte1) & 0x0050));
rightOrOperand = ((uint16_t) byte2);
result = leftOrOperand | rightOrOperand;
代码片段 3:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = (uint16_t) (((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2));
为什么第一个代码片段会产生警告,而其他代码片段却不会?具体是什么导致了警告?
我觉得这很费解。第一个片段中的警告暗示整数提升发生在按位或操作中,尽管操作数是显式转换的。第二个片段演示了按位或运算本身不会导致整数提升。如果保留操作顺序,第三个代码片段执行与第一个代码片段相同的操作,但在分配结果变量之前转换按位或的结果。关于强制转换和按位或运算之间的相互作用,我显然有一些不明白的地方。任何有助于澄清我的理解的帮助将不胜感激!
其他可能相关的信息:
- gcc (GCC) 4.8.5 20150623(我无法升级,但这似乎也发生在较新的版本上)
- -std=c11
- -默认优化(未提供设置)和禁用优化 (-O0) 时出现 Wconversion 警告
提前致谢!
按位或运算符 |
和按位与运算符 &
都对两个操作数执行整数提升。其中一个操作数是强制转换的结果这一事实并没有改变这一点。
-Wconversion
标志对于它所警告的内容往往有点过分热情。给定 32 位 int
,从 uint16_t
到 int
的转换将 不会 改变它的值。
C 标准确实指定 int
的最小范围是 -32767 到 32767,因此具有此限制的实现可能会看到值的变化,尽管您很难找到在这种情况下运行 gcc 的系统。
但是这个特殊的警告被强制转换消音了。来自手册页:
-Wconversion
Warn for implicit conversions that may alter a value. This includes
conversions between real and integer, like "abs (x)" when "x" is
"double"; conversions between signed and unsigned, like "unsigned
ui = -1"; and conversions to smaller types, like "sqrtf (M_PI)". Do
not warn for explicit casts like "abs ((int) x)" and "ui =
(unsigned) -1", or if the value is not changed by the conversion like
in "abs (2.0)". Warnings about conversions between signed and
unsigned integers can be disabled by using -Wno-sign-conversion.
For C++, also warn for confusing overload resolution for
user-defined conversions; and conversions that never use a type
conversion operator: conversions to "void", the same type, a base
class or a reference to them. Warnings about conversions between
signed and unsigned integers are disabled by default in C++ unless
-Wsign-conversion is explicitly enabled.
Why does the first code snippet produce the warning, but the others do not? What specifically is causing the warning?
((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2)
是一个 int
被分配给一个 uint16_t
.
((uint16_t) (((uint16_t) byte1) & 0x0050))
是 uint16_t
.
((uint16_t) byte2)
也是一个 uint16_t
.
uint16_t | uint16_t
首先在 |
.
之前将操作数提升为 int
代码正在将 int
分配给 uint16_t
- 因此出现警告。
在第二个片段中,编译器更好地理解了两个 uint16_t
的或运算(结果也是 int
)不会导致下转换为 uint16_t
的转换问题。第一个只是有点太复杂了,编译器无法推断出任何问题。
在 3 号中,最后的演员阵容消除了任何向下转换问题。
备选方案:使用 unsigned
常量:0x0050u
和 unsigned
数学 unsigned 类型,例如 uint16_t
.
uint8_t byte1 = 0xF0u;
uint8_t byte2 = 0x0Fu;
// v-------------v unsigned result
// v-----v unsigned constant
uint16_t result = (byte1 & 0x0050u) | byte2;
// ^-----------------------^ unsigned result
// ^--------------------------------^ initializing: unsigned to uint16_t
一个讨厌的编译器可能仍然抱怨缩小初始化。
// Non-cast alternative
uint16_t result = UINT16_MAX & ((byte1 & 0x0050u) | byte2);
// Cast alternative
uint16_t result = (uint16_t) ((byte1 & 0x0050u) | byte2);
代码片段 1(如下所示)产生以下 -Wconversion 警告:
debug_Wconversion.c:10:57: warning: conversion to ‘uint16_t’ from ‘int’ may alter its value [-Wconversion]
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
^
代码片段 2 和 3 不产生 -Wconversion 警告。
代码片段 1:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = ((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2);
代码片段 2:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
uint16_t leftOrOperand;
uint16_t rightOrOperand;
leftOrOperand = ((uint16_t) (((uint16_t) byte1) & 0x0050));
rightOrOperand = ((uint16_t) byte2);
result = leftOrOperand | rightOrOperand;
代码片段 3:
uint8_t byte1 = 0xF0;
uint8_t byte2 = 0x0F;
uint16_t result;
result = (uint16_t) (((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2));
为什么第一个代码片段会产生警告,而其他代码片段却不会?具体是什么导致了警告?
我觉得这很费解。第一个片段中的警告暗示整数提升发生在按位或操作中,尽管操作数是显式转换的。第二个片段演示了按位或运算本身不会导致整数提升。如果保留操作顺序,第三个代码片段执行与第一个代码片段相同的操作,但在分配结果变量之前转换按位或的结果。关于强制转换和按位或运算之间的相互作用,我显然有一些不明白的地方。任何有助于澄清我的理解的帮助将不胜感激!
其他可能相关的信息:
- gcc (GCC) 4.8.5 20150623(我无法升级,但这似乎也发生在较新的版本上)
- -std=c11
- -默认优化(未提供设置)和禁用优化 (-O0) 时出现 Wconversion 警告
提前致谢!
按位或运算符 |
和按位与运算符 &
都对两个操作数执行整数提升。其中一个操作数是强制转换的结果这一事实并没有改变这一点。
-Wconversion
标志对于它所警告的内容往往有点过分热情。给定 32 位 int
,从 uint16_t
到 int
的转换将 不会 改变它的值。
C 标准确实指定 int
的最小范围是 -32767 到 32767,因此具有此限制的实现可能会看到值的变化,尽管您很难找到在这种情况下运行 gcc 的系统。
但是这个特殊的警告被强制转换消音了。来自手册页:
-Wconversion
Warn for implicit conversions that may alter a value. This includes conversions between real and integer, like "abs (x)" when "x" is "double"; conversions between signed and unsigned, like "unsigned ui = -1"; and conversions to smaller types, like "sqrtf (M_PI)". Do not warn for explicit casts like "abs ((int) x)" and "ui = (unsigned) -1", or if the value is not changed by the conversion like in "abs (2.0)". Warnings about conversions between signed and unsigned integers can be disabled by using -Wno-sign-conversion.
For C++, also warn for confusing overload resolution for user-defined conversions; and conversions that never use a type conversion operator: conversions to "void", the same type, a base class or a reference to them. Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless -Wsign-conversion is explicitly enabled.
Why does the first code snippet produce the warning, but the others do not? What specifically is causing the warning?
((uint16_t) (((uint16_t) byte1) & 0x0050)) | ((uint16_t) byte2)
是一个 int
被分配给一个 uint16_t
.
((uint16_t) (((uint16_t) byte1) & 0x0050))
是 uint16_t
.
((uint16_t) byte2)
也是一个 uint16_t
.
uint16_t | uint16_t
首先在 |
.
int
代码正在将 int
分配给 uint16_t
- 因此出现警告。
在第二个片段中,编译器更好地理解了两个 uint16_t
的或运算(结果也是 int
)不会导致下转换为 uint16_t
的转换问题。第一个只是有点太复杂了,编译器无法推断出任何问题。
在 3 号中,最后的演员阵容消除了任何向下转换问题。
备选方案:使用 unsigned
常量:0x0050u
和 unsigned
数学 unsigned 类型,例如 uint16_t
.
uint8_t byte1 = 0xF0u;
uint8_t byte2 = 0x0Fu;
// v-------------v unsigned result
// v-----v unsigned constant
uint16_t result = (byte1 & 0x0050u) | byte2;
// ^-----------------------^ unsigned result
// ^--------------------------------^ initializing: unsigned to uint16_t
一个讨厌的编译器可能仍然抱怨缩小初始化。
// Non-cast alternative
uint16_t result = UINT16_MAX & ((byte1 & 0x0050u) | byte2);
// Cast alternative
uint16_t result = (uint16_t) ((byte1 & 0x0050u) | byte2);