程序应该崩溃,但不会崩溃

时间:2020-07-21 06:47:54

标签: arrays c memory undefined-behavior

#include <stdio.h>
#define CHAR_ROW_SIZE 4
int charTable[CHAR_ROW_SIZE ][2] = {
  {'X', 'Z'},
  {'J', 'L'},
  {'F', 'C'},
  {'A', 'B'}
};

int main()
{
    printf("char element %c\n", charTable[3][1]); //fine
    printf("char element %c\n", charTable[3][8]); // accessing 4th row's 9th element which is not valid 
    printf("char element %c\n", charTable[85][0]);// accessing 86th row's first element which is not valid 

    return 0;
}

输出:

char element B                                                                                                                                                                     
char element                                                                                                                                                                       
char element

据我了解,C \ C ++实际上不对数组进行任何边界检查。取决于操作系统,以确保您正在访问有效的内存。所以这是未定义的行为。

但是在这里我可以看到不同机器上的不变行为。即程序不会随时崩溃。

2 个答案:

答案 0 :(得分:5)

但是在这里我可以看到不同机器上的不变行为。即程序不会随时崩溃。

在这里,崩溃(或分段错误)既不是期望的行为也不是保证的行为,其行为是 undefined

这里的底线是,未定义的行为是访问超出范围的内存(即,不属于您的进程地址空间的内存位置)。有时,使用UB的代码似乎可以正常工作,没有任何分段错误,产生一些随机值(包括0),使人产生了“工作正常”的错觉,但事实并非如此!

答案 1 :(得分:0)

除调用abort();的程序外,C标准没有“应崩溃”的程序概念。编写C标准的目的是允许实现以对编译器客户最有用的任何方式处理越界数组访问。取决于客户要完成的工作,最有用的操作方法可能是:

  1. 在编译器可以识别出正在进行越界访问的情况下进行捕获。
  2. 扩展语言的语义,以便如果程序员知道所计算的地址处的内容,则代码可以访问具有该副作用的对象[并且如果程序员不知道,则代码仍然可以访问它] 。
  3. 执行访问而不考虑其有效性,但不允许访问可能与程序执行的其他操作交互。

在编写标准时,存在以三种方式表现的实现,以及三种方式中每种方式最有用的程序。该标准的作者并没有试图就哪种方法在任何特定情况下最适合做出任何判断,而是希望任何希望出售编译器的人都将寻求以他们的客户认为最有用的方式来处理代码-一种行之有效的哲学当语言趋势是由注重客户利益的编译器编写者驱动的时候。