【问题标题】:Clang loop optimizations causes a segmentation fault?Clang 循环优化会导致分段错误?
【发布时间】:2018-01-31 15:56:48
【问题描述】:

我正在为“二分搜索”编写代码。与此同时,我写了一些代码来查看我的起点、中间点和终点在哪里。为此,我打印了一个字符串,其中开始、中间和结束的数字用方括号括起来。因为这导致我出现分段错误,所以我复制了代码并将其压缩为导致问题的最少代码量。

这是代码:

#include <stdio.h>
#include <string.h>

int main(void)
{
    int values[9] = {1, 3, 6, 9, 10, 14, 16, 17, 21};
    int n = sizeof(values) / sizeof(int); // <-- make this is a "const", and the "segmentation fault" goes away

    char buf[20] = "";
    char num[6] = "";

    for(int i = 0; i < n; i++)
    {
        printf("i: %i, n: %i\n", i, n);

        sprintf(num, "[%i] ", values[i]);

        strcat(buf, num);
    }

    return 0;
}

用这一行编译:

clang -std=c99 -Wall -Werror loop.c -o loop

不知何故,“n”被改变了,尽管它不应该被改变。至少不是我改的。

那么为什么会这样呢?

【问题讨论】:

  • 顺便说一句,不要亲自投票。我没有投票,但我想选民投票是因为这个问题对其他人没有太大用处——这可能不是他们在查找自己的问题时要寻找的东西。您在将问题简化为可重现的示例方面做得很好。

标签: c clang


【解决方案1】:

您将 buf 声明为 20 个 char 的数组,但您将“[1] [3] [6] [9] [10] [14] [16] [17] [21]” 写入它,即 41 char,包括终止的空值。在循环期间,strcat 会超出 buf 并将数据写入不应写入的内存,这会破坏进程中的其他内容。

【讨论】:

  • 好的。这就说得通了。但是为什么将“n”设为 const 来解决这个问题呢?
  • @IkemKrueger:制作n const 并不能解决问题。它只是碰巧导致编译器改变了它在内存中组织事物的方式,结果缓冲区溢出破坏了与以前不同的数据,这种方式在程序的可观察行为中可能并不明显。
  • 未定义的行为可能会很棘手。如果您将n 的声明移动到所有缓冲区之后,它也恰好不是段错误(至少在我的系统上)。使用strncat 等更安全的函数可以通过指定缓冲区的长度来帮助您避免缓冲区溢出。
  • 最后一点与strcat 相关,在这样的循环中使用它可能效率很低,因为每次调用它时都必须重新计算字符串的长度,并且作为字符串增长,因此计算其长度的时间量也会增长。这被称为 Sclemiel The Painter 算法。 en.wikichip.org/wiki/schlemiel_the_painter%27s_algorithm 。最好随时跟踪字符串的长度,然后您可以将其用作缓冲区的偏移量,直接复制到字符串的末尾,而不是重新计算其长度的代价高昂。
猜你喜欢
  • 2015-09-03
  • 1970-01-01
  • 2020-12-14
  • 2017-11-21
  • 2011-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-06
相关资源
最近更新 更多