编译器警告(等级 4)C4754
比较中的算术运算的转换规则意味着无法执行一个分支。
发出了 C4754 警告,因为比较的结果总是相同。 这可能表示条件的其中一个分支绝不会执行,原因最可能是关联的整数表达式不正确。 此代码缺陷通常在对 64 位体系结构执行了不正确的整数溢出检查时发生。
整数转换规则很复杂,并且有很多微小的缺陷。 作为解决每个 C4754 警告的替代方法,你可以更新代码以使用 SafeInt 库。
示例
此示例生成 C4754:
// C4754a.cpp
// Compile with: /W4 /c
#include "errno.h"
int sum_overflow(unsigned long a, unsigned long b)
{
unsigned long long x = a + b; // C4754
if (x > 0xFFFFFFFF)
{
// never executes!
return EOVERFLOW;
}
return 0;
}
加法 a + b
可能导致在将结果向上转换为 64 位值并分配给 64 位变量 x
前发生算术溢出。 这意味着,对 x
的检查是多余的,永远不会捕获到溢出。 在这种情况下,编译器将发出以下警告:
Warning C4754: Conversion rules for arithmetic operations in the comparison at C4754a.cpp (7) mean that one branch cannot be executed. Cast '(a + ...)' to 'ULONG64' (or similar type of 8 bytes).
若要消除此警告,您可以更改赋值语句以将操作数强制转换为 8 字节值:
// Casting one operand is sufficient to force all the operands in
// the addition be upcast according to C/C++ conversion rules, but
// casting both is clearer.
unsigned long long x =
(unsigned long long)a + (unsigned long long)b;
下一个示例也会生成 C4754。
// C4754b.cpp
// Compile with: /W4 /c
#include "errno.h"
int wrap_overflow(unsigned long a)
{
if (a + sizeof(unsigned long) < a) // C4754
{
// never executes!
return EOVERFLOW;
}
return 0;
}
sizeof()
运算符返回了 size_t
,其大小依赖于体系结构。 该代码示例适用于其中的 size_t
是 32 位类型的 32 位体系结构。 然而,在 64 位体系结构中,size_t
是 64 位类型。 整数的转换规则意味着,a
在表达式 a + b < a
中将向上转换 64 位值,就如同采用 (size_t)a + (size_t)b < (size_t)a
形式一样。 当 a
和 b
为 32 位整数时,64 位加法运算永远不会溢出,并且永远不会应用约束。 因此,代码永远不会检测在 64 位体系结构中检测到整数溢出条件。 此示例导致编译器发出以下警告:
Warning C4754: Conversion rules for arithmetic operations in the comparison at C4754b.cpp (7) mean that one branch cannot be executed. Cast '4' to 'ULONG' (or similar type of 4 bytes).
请注意,警告消息在警告分析遇到违规代码时显式列出了常量值 4 而不是原始的源字符串,sizeof(unsigned long)
已转换为常量。 因此,你可能必须追查源代码的哪个表达式与警告消息中的常量值关联。 解析为 C4754 警告消息中的常量的最常见的代码来源是表达式,如 sizeof(TYPE)
和 strlen(szConstantString)
。
在这种情况下,修复后的代码将类似于形式:
// Casting the result of sizeof() to unsigned long ensures
// that all the addition operands are 32-bit, so any overflow
// is detected by the check.
if (a + (unsigned long)sizeof(unsigned long) < a)
注意:编译器警告中提到的行号是语句的最后一行。 在有关分布到多个行的复杂条件语句的警告消息中,具有行代码缺陷的行可能是所报告的行前面几行的行。 例如:
unsigned long a;
if (a + sizeof(unsigned long) < a || // incorrect check
condition1() ||
a == 0) { // C4754 warning reported on this line
// never executes!
return INVALID_PARAMETER;
}
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈