微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C 程序在 Linux 命令行中导致分段错误但在 gdb 中正常退出

如何解决C 程序在 Linux 命令行中导致分段错误但在 gdb 中正常退出

我编写了以下 C 程序来打印出整数的每个字节:

#include <stdio.h>
#include <stdlib.h>
union bytes
{   int number;
    char bytes[sizeof(int)];
};

int main(int argc,char **argv)
{   for (int i=1; i < argc; i++)
    {
        int* x;
        *x = atoi(argv[i]);
        union bytes bytes_of_x;
        bytes_of_x.number = *x;
        for (int j=0; j < sizeof(int); j++)
        {
            unsigned char b = *((unsigned char*)x + j);
            bytes_of_x.bytes[j] = b;
        }
        for (int k=0; k < sizeof(int); k++)
        {
            printf("Byte %d = %x\n",k+1,bytes_of_x.bytes[k]);
        }
    }
    return 0;
}

它编译得很好,没有警告,但是当我在命令行上运行它时(使用 ./progname 整数),它返回了一个分段错误

我用几个不同的输入在 gdb 中运行程序,但每次它都正常退出

由于 gdb 未识别任何错误,我应该如何确定分段错误的来源?

解决方法

您尚未为 x 分配任何内存。这个变量是一个指针,但你在使用它时没有分配任何有效的内存来使用。

您需要像这样为 malloc 分配 x 内存:

int *x = malloc(sizeof(int));

然后记得free它,就像这样:

free(x);

在每次 for 循环迭代结束时。

但是,我怀疑是否需要以这种方式实际声明 x。为什么不先将 argv[i] 参数分配给在堆栈上声明的 int 变量,然后初始化第二个变量以指向它,如下所示:

int y = atoi(argv[i]);
int *x = &y;

另外,你说你的程序“编译良好,没有警告”。这向我表明您还没有使用至少一些 基本编译标志来编译您的代码,这些标志会警告您 x 未初始化。例如,使用 gcc:

gcc -Wall program.c

很容易发现这个错误,并且

gcc -Wall -Werror program.c

会完全阻止编译“成功”。

请阅读编译器的手册页以了解有关编译标志的更多信息,这将节省您的时间和麻烦。

另外:另一个值得研究的有用工具是 valgrind - 它在检测未初始化的变量、内存泄漏等方面做得非常出色。

,

编译正常,没有警告

您需要打开附加警告,或者您需要更好的编译器。

使用 GCC 8.3.0:

gcc -g t.c -Wall
t.c: In function ‘main’:
t.c:12:12: warning: ‘x’ may be used uninitialized in this function [-Wmaybe-uninitialized]
         *x = atoi(argv[i]);
         ~~~^~~~~~~~~~~~~~~

gcc -g t.c -Wall -Wextra
t.c: In function ‘main’:
t.c:15:25: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare]
         for (int j=0; j < sizeof(int); j++)
                         ^
t.c:20:25: warning: comparison of integer expressions of different signedness: ‘int’ and ‘long unsigned int’ [-Wsign-compare]
         for (int k=0; k < sizeof(int); k++)
                         ^
t.c:12:12: warning: ‘x’ may be used uninitialized in this function [-Wmaybe-uninitialized]
         *x = atoi(argv[i]);
         ~~~^~~~~~~~~~~~~~~

正如其他答案已经说过的那样,您正在通过未初始化的指针进行写入,这会导致未定义的行为。 UB 的意思是:任何事情都可能发生,包括程序在一台机器上运行,但在另一台机器上不能运行,或者在 GDB 下运行而不在 GDB 之外运行,反之亦然。

由于 gdb 未识别任何错误,我应该如何确定分段错误的来源?

您可以使用 GDB 进行事后调试:

# Set core dump size to be unlimited
ulimit -c unlimited

# Generate a core dump
./a.out 42
Segmentation fault (core dumped)

gdb a.out core    # now use GDB to debug the crash.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。