程序应该崩溃但它没有
Program should crash but it doesn't
#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++ 实际上并没有对数组进行任何边界检查。它取决于 OS 以确保您正在访问有效内存。所以这是未定义的行为。
但在这里我可以看到在另一台机器上始终存在相同的行为。即程序不会随时崩溃。
But here I can see the constant same behavior in a different machine. i.e program doesn't crash anytime.
在这里,崩溃(或分段错误)既不是期望的也不是保证的行为,行为是 undefined.
这里的底线是,访问超出限制的内存(即不属于您的进程地址 space 的内存位置)是未定义的行为。有时带有 UB 的代码似乎工作得很好,没有任何分段错误,产生一些随机值,包括 0,造成事情“工作正常”的错觉,但事实并非如此!
除了那些调用 abort();
的程序外,C 标准没有“应该崩溃”的程序概念。编写 C 标准是为了允许实现以对编译器客户最有用的任何方式处理越界数组访问。根据客户想要完成的目标,最有用的行动方案可能是:
- 在编译器可以识别正在发生越界访问的情况下陷入陷阱。
- 扩展语言的语义,这样如果程序员知道计算地址处的内容,代码就可以访问该对象并产生任何副作用[如果程序员不知道,代码将访问它无论如何]。
- 执行访问而不考虑其有效性,但不允许访问可能与程序执行的其他操作交互的可能性。
编写标准时,存在以所有三种方式运行的实现,以及三种方式中的每一种方式最有用的程序。该标准的作者并没有试图对哪种方法在任何特定情况下最好做出任何判断,而是期望任何希望销售编译器的人都将寻求以客户认为最有用的任何方式处理代码——这一理念行之有效好吧,当语言趋势是由关心客户利益的编译器作者推动的时候。
#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++ 实际上并没有对数组进行任何边界检查。它取决于 OS 以确保您正在访问有效内存。所以这是未定义的行为。
但在这里我可以看到在另一台机器上始终存在相同的行为。即程序不会随时崩溃。
But here I can see the constant same behavior in a different machine. i.e program doesn't crash anytime.
在这里,崩溃(或分段错误)既不是期望的也不是保证的行为,行为是 undefined.
这里的底线是,访问超出限制的内存(即不属于您的进程地址 space 的内存位置)是未定义的行为。有时带有 UB 的代码似乎工作得很好,没有任何分段错误,产生一些随机值,包括 0,造成事情“工作正常”的错觉,但事实并非如此!
除了那些调用 abort();
的程序外,C 标准没有“应该崩溃”的程序概念。编写 C 标准是为了允许实现以对编译器客户最有用的任何方式处理越界数组访问。根据客户想要完成的目标,最有用的行动方案可能是:
- 在编译器可以识别正在发生越界访问的情况下陷入陷阱。
- 扩展语言的语义,这样如果程序员知道计算地址处的内容,代码就可以访问该对象并产生任何副作用[如果程序员不知道,代码将访问它无论如何]。
- 执行访问而不考虑其有效性,但不允许访问可能与程序执行的其他操作交互的可能性。
编写标准时,存在以所有三种方式运行的实现,以及三种方式中的每一种方式最有用的程序。该标准的作者并没有试图对哪种方法在任何特定情况下最好做出任何判断,而是期望任何希望销售编译器的人都将寻求以客户认为最有用的任何方式处理代码——这一理念行之有效好吧,当语言趋势是由关心客户利益的编译器作者推动的时候。