【问题标题】:what have gcc done when I try to make a array overflow?当我尝试使数组溢出时,gcc 做了什么?
【发布时间】:2013-04-05 13:51:09
【问题描述】:

我尝试了一段导致数组溢出的代码,但是当我用 gcc 编译它时发生了一些意想不到的事情。下面是代码:

#include <stdio.h>

int main(int argc, const char *argv[])
{
    int a[] = {0,2,4,7};
    int size = sizeof(a)/sizeof(int);
    int i;
    printf("%d, %X\n", size, &a);
    a[4] = 6;
    printf("%d, %X\n", size, &a);
    a[5] = 78;
    printf("%d, %X\n", size, &a);
    a[6] = 65;
    printf("%d, %X\n", size, &a);
    for (i = 0; i < size; i++) {
        printf("%d, ", a[i]);
    }
    printf("%d, %d, %d\n", a[size], a[size+1], a[size+2]);
    printf("\n");
    return 0;
}

结果是:

4, BFC4DDF8
6, BFC4DDF8
6, BFC4DDF8
6, BFC4DDF8
0, 2, 4, 7, 6, 5, 65, 0, 0

所以在代码中,我并没有改变size的值,但是当它运行时,它确实自己改变了!那么谁能告诉我为什么会这样?

PS:gcc 版本是 4.8.0。

根据@NPE 的回答,我检查了size 的地址,它实际上位于内存中a 之后。

但是当我添加一段代码时

printf("%X\n", &size);

之前

printf("%d, %X\n", size, &a);

结果是

BFC39108
4, BFC3910C
4, BFC3910C
4, BFC3910C
4, BFC3910C
0, 2, 4, 7, 4, 78, 65

此时,size 位于内存中 a 之前。


事实上,无论我在哪里打印size 的地址,它都位于a 的地址之前;如果我不打印size 的地址,它就位于a 的地址之后。那么它仍然是编译器的未定义行为吗?

【问题讨论】:

  • 我预计 size 的值不应该改变。
  • 一旦你有未定义的行为,你就不能再指望它了。

标签: c arrays gcc


【解决方案1】:

由于您写到了a 的末尾,所以您的程序有undefined behaviour。这意味着它可以以任何它喜欢的方式行事,包括你正在观察的方式。

实际发生的情况是size 恰好位于内存中a 之后,并且出现以下越界赋值:

a[4] = 6;

覆盖size

请注意,如果您使用不同的编译器或不同的编译器设置,或者对程序进行看似无关紧要的更改,代码可能会以其他方式失败。或者它可能在您的整个测试过程中运行良好,然后在您的客户面前爆炸。

【讨论】:

  • 但似乎size每次运行时都位于a之后的内存中。
  • @Jude:计算机是相当可预测的,如果你给他们同样的指令,他们会做同样的事情。因此,您不应该感到惊讶。该行为仍未定义,明天size 可能不会位于a 之后。
  • 我刚刚编辑了问题,如果我在任何地方打印size 的地址,它就位于a 的地址之前。那么这仍然是编译器的彩蛋吗?
【解决方案2】:

您覆盖了 a[] 数组末尾的内存,因此覆盖了 size 的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 2020-05-31
    • 2021-04-22
    相关资源
    最近更新 更多