void main() {
unsigned int a = 0;
if (a - 10 < 0) {
printf("error!\n");
}
}
我们知道这个比较是行不通的,因为 a-10 是一个很大的无符号整数,它不能小于 0.
为了避免这种情况,我尝试这样做:
void main() {
unsigned int a = 0;
int b = 0;// or const int b = 0;
if (a - 10 < b) {
printf("error!\n");
}
}
这将使用 Visual Studio 2022 17.2.4.
获得
warning C4018
然而,当我使用gcc 4.8.5时,完全没有警告。
有没有办法避免编码器将有符号数与无符号变量进行比较?
更新: 更复杂的情况可能是这样的:
struct s{
unsigned int len;
char *buffer;
} *a;
int not_safe(struct s *ptr){
if(ptr->len - sizeof(struct s) < 0){
return 0;
}
return 1;
}
程序员可能没有意识到这样的比较是错误的。我 希望我们能有一个安全的方法让程序员避免这种情况。
如果您将
unsigned int
操作数转换为 int
:
if ((int)a - 10 < 0)
然后使用类型
int
完成所有数学运算。
或者,你可以做一点代数:
if (a < 10)
彻底避免问题
请研究C正式调用的内容通常的算术转换隐式类型提升规则。 TL;DR 是,如果您有两个大小相同但符号不同的整数,则有符号的将转换为无符号的。
您可以显式地将无符号操作数转换为有符号操作数。或者你可以让有符号的操作数比无符号的更大,比如
int64_t
,在这种情况下,unsigned int
(可能是 16 或 32 位)将被转换为 int64_t
.
但这并不能解决您的根本问题,即这一行:
if(ptr->len - sizeof(struct s) < 0)
这从一开始就没有任何意义。并且将
ptr->len
转换为 int64_t
可能无助于任何大小 sizeof
返回一个 size_t
,它保证是一个大的无符号整数类型。只需将其替换为:
if(sizeof(struct s) > ptr->len)
或者,如果您愿意,将整个功能更改为以下常见的最佳做法:
bool not_safe (const struct s* ptr) {
return sizeof(struct s) > ptr->len;
}
灵感来自@dbush.
将
-Werror -Wextra
添加到 gcc,-Wextra
将提醒编码器,-Werror
将停止构建,因此我们可以阻止编码器创建错误。