我不知道为什么这段代码符合:
int array[100];
array[-50] = 100; // Crash!!
...编译器仍可正常编译,无需编译错误和警告。
那为什么要编译呢?
答案 0 :(得分:7)
array[-50] = 100;
实际上意味着:
*(array - 50) = 100;
考虑这段代码:
int array[100];
int *b = &(a[50]);
b[-20] = 5;
此代码有效且不会崩溃。编译器无法知道代码是否会崩溃以及程序员想要对数组做什么。所以它没有抱怨。
最后,请注意,在查找代码中的错误时,不应该依赖编译器警告。编译器不会找到你的大部分错误,他们几乎没有尝试为你提供一些提示来缓解错误修正过程(有时他们甚至可能会弄错并指出,有效的代码是错误的)。此外,标准实际上从不要求编译器发出警告,因此这些只是编译器实现者的良好意愿。
答案 1 :(得分:6)
它编译是因为表达式array[-50]
被转换为等价的
*(&array[0] + (-50))
这是另一种说法“取内存地址&array[0]
并添加-50倍sizeof(array[0])
,然后解释生成的内存地址的内容及其后面的内容{{1按照通常的指针算术规则。这是一个完全有效的表达式,其中int
可能真的是任何整数(当然它不需要是编译时常量)。
现在肯定是因为-50
是编译时常量,并且因为访问数组的第50个元素几乎总是错误,所以编译器可以(和也许应该)为此发出警告。
但是,我们还应该考虑检测这种特定条件(静态索引到具有明显无效索引的数组)是您不希望在实际代码中看到的内容。因此,编译器团队的资源可能会更好地用于其他事情。
将此与其他 希望在实际代码中看到的-50
构造进行对比(如果只是因为它很容易犯这个错误)并且很难调试( eye可以轻松地将if (answer = 42)
视为=
,而==
可以立即显示出来。在这些情况下,编译器警告会更有效率。
答案 2 :(得分:2)
True compilers do(注意:需要将编译器切换到clang 3.2,gcc不是用户友好的)
Compilation finished with warnings:
source.cpp:3:4: warning: array index -50 is before the beginning of the array [-Warray-bounds]
array[-50] = 100;
^ ~~~
source.cpp:2:4: note: array 'array' declared here
int array[100];
^
1 warning generated.
如果你有一个较小的(*)编译器,你可能需要手动设置警告。
(*)即用户友好性
答案 3 :(得分:1)
编译器不需要在编译时捕获所有潜在的问题。 C标准允许在运行时出现未定义的行为(执行此程序时会发生这种情况)。您可以将其视为不捕获此类错误的合法借口。
虽然有编译器和静态程序分析器可以捕获这样的琐碎错误。
答案 4 :(得分:0)
括号内的数字只是一个索引。它告诉您内存中要查找您要求的号码的步数。 array[2]
表示从数组的开头开始,然后向前跳两次。
你刚刚告诉它向后跳50次,这是一个有效的陈述。但是,我无法想象有这么好的理由......