为什么 GCC 不检测变量初始化溢出?

aka*_*roc -5 c initialization integer-overflow

为什么编译没有错误呢?我究竟做错了什么?

#include <stdio.h>

int main (){
    int n1 = 90, n2 = 93, n3 = 95;
    int i = 2147483647;
    int ii = 2147483646;
    int iii = 2147483650;
    char c1[50] = {'\0'};
    char c2[50] = {'\0'};
    char c3[50] = {'\0'};

    n1 = sprintf(c1, "%d", i+i);
    n2 = sprintf(c2, "%d", ii);
    n3 = sprintf(c3, "%d", iii);
    printf("n1 = %d, n2 = %d, n3 = %d\n  i = |%s| \n ii = |%s|\niii = |%s|\n", n1, n2, n3, c1, c2, c3);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)
#include <stdio.h>

int main (){
    int n1 = 90, n2 = 93, n3 = 95;
    int i = 2147483647;
    int ii = 2147483646;
    int iii = 2147483650;
    char c1[50] = {'\0'};
    char c2[50] = {'\0'};
    char c3[50] = {'\0'};

    n1 = sprintf(c1, "%d", i+i);
    n2 = sprintf(c2, "%d", ii);
    n3 = sprintf(c3, "%d", iii);
    printf("n1 = %d, n2 = %d, n3 = %d\n  i = |%s| \n ii = |%s|\niii = |%s|\n", n1, n2, n3, c1, c2, c3);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

我想%d不能超过 int,但它是经过编译的,结果是:

gcc filename -Wall -Wextra -Werror
Run Code Online (Sandbox Code Playgroud)

我本来以为会出现 GCC 错误。

jxh*_*jxh 12

初始化时出现错误iii,提供的常量不适合int

\n

如果您启用 .GCC 将诊断此问题-pedantic。从文档中:

\n
\n

-Wpedantic
\n -pedantic
\n发出严格的 ISO C 和 ISO C++ 要求的所有警告;拒绝所有使用禁止扩展的程序,以及一些不遵循 ISO C 和 ISO C++ 的其他程序。对于 ISO C,遵循由使用的任何 -std 选项指定的 ISO C 标准版本。

\n
\n

这样做时,我收到错误:

\n
.code.tio.c: In function \xe2\x80\x98main\xe2\x80\x99:\n.code.tio.c:7:15: error: overflow in conversion from \xe2\x80\x98long int\xe2\x80\x99 to \xe2\x80\x98int\xe2\x80\x99 changes value from \xe2\x80\x982147483650\xe2\x80\x99 to \xe2\x80\x98-2147483646\xe2\x80\x99 [-Werror=overflow]\n     int iii = 2147483650;\n               ^~~~~~~~~~\ncc1: all warnings being treated as errors\n
Run Code Online (Sandbox Code Playgroud)\n

在线尝试一下!

\n
\n

其他问题

\n
导致有符号整数溢出的算术
\n

算术运算i+1会触发有符号整数溢出,这具有未定义的行为,因此编译器可以自由地对该代码执行任何操作。

\n

请注意,该+运算符的两个操作数都具有类型int,因此如果生成任何结果,它将是一个int。然而,由于有符号整数溢出是未定义的,因此可能不会生成任何结果(例如,程序可能会停止),或者可能会生成随机结果,或者可能会发生与您的观察相匹配的其他溢出行为。

\n

在一般情况下,编译器没有任何方法可以知道任何特定操作是否实际上会导致溢出。在这种情况下,静态代码分析可能已经揭示了这一点。我相信 GCC 确实执行了一些基本的静态代码分析,但不需要识别每个未定义行为的实例。

\n
使用sprintf代替snprintf
\n

虽然在您的特定上下文中使用它是安全的sprintf,但通常更推荐用于snprintf防范缓冲区溢出漏洞。snprintf只需要一个额外的参数来指示缓冲区的大小,它就会NUL为您终止字符串。

\n