如何避免将无符号整数与有符号数进行比较?

问题描述 投票:0回答:3
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;
}

程序员可能没有意识到这样的比较是错误的。我 希望我们能有一个安全的方法让程序员避免这种情况。

c visual-studio security gcc
3个回答
0
投票

如果您将

unsigned int
操作数转换为
int

if ((int)a - 10 < 0)

然后使用类型

int
完成所有数学运算。

或者,你可以做一点代数:

if (a < 10)

彻底避免问题


0
投票

请研究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;
}

0
投票

灵感来自@dbush.

-Werror -Wextra
添加到 gcc,
-Wextra
将提醒编码器,
-Werror
将停止构建,因此我们可以阻止编码器创建错误。

© www.soinside.com 2019 - 2024. All rights reserved.