为什么这段代码在没有警告的情况下编译

Why does this code compile without warnings?

本文关键字:警告 编译 情况下 段代码 代码 为什么      更新时间:2023-10-16

我不知道为什么这段代码符合:

int array[100];
array[-50] = 100; // Crash!!

。编译器仍然可以正确编译,没有编译错误和警告。

那么它为什么要编译呢?

array[-50] = 100;

实际上在这里意味着:

*(array - 50) = 100;

请考虑以下代码:

int array[100];
int *b = &(a[50]);
b[-20] = 5;

此代码有效,不会崩溃。编译器无法知道代码是否会崩溃以及程序员想对数组做什么。所以它不抱怨。

最后,请注意,在查找代码中的错误时不应依赖编译器警告。编译器不会找到你的大部分错误,他们几乎不会尝试为你提供一些提示来简化错误修复过程(有时他们甚至可能被误解并指出,有效的代码是错误的(。此外,该标准实际上从不要求编译器发出警告,因此这些只是编译器实现者的善意行为。

它编译是因为表达式array[-50]被转换为等效的

*(&array[0] + (-50))

这是另一种说法"将内存地址&array[0]sizeof(array[0]) -50 倍添加到其中,然后将生成的内存地址的内容及其后面的内容解释为int",按照通常的指针算术规则。这是一个完全有效的表达式,其中-50可能真的是任何整数(当然它不需要是编译时常量(。

现在肯定是真的,因为这里的-50是一个编译时常量,并且由于访问数组的第 50 个元素几乎总是一个错误,编译器可以(也许应该(为此生成警告。

但是,我们还应该考虑到,检测此特定条件(静态索引到具有明显无效索引的数组(是您不希望在实际代码中看到的。因此,编译器团队的资源可能会更好地用于其他事情。

将其与其他结构(如if (answer = 42)(进行对比,这些结构确实希望在实际代码中看到(如果只是因为很容易打错字(并且难以调试(眼睛可以轻松地将=读取为==,而该-50立即突出(。在这些情况下,编译器警告的效率要高得多。

编译器不需要在编译时捕获所有潜在问题。C 标准允许在运行时出现未定义的行为(这是执行此程序时发生的情况(。您可以将其视为不捕获此类错误的法律借口。

不过,有一些编译器和静态程序分析器可以捕获像这样的琐碎错误。

真正的编译器可以(注意:需要将编译器切换到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.

如果您有较小的 (*( 编译器,则可能需要手动设置警告。

(*( 即,不太用户友好

括号

内的数字只是一个索引。 它告诉您在内存中执行多少步才能找到您请求的号码。 array[2] 表示从数组的开头开始,向前跳两次。

你刚刚告诉它向后跳50次,这是一个有效的说法。 但是,我无法想象这样做有充分的理由......