访问 int (*foo)[3] 的索引 4 时没有警告
No warnings when accessing index 4 of int (*foo)[3]
令我惊讶的是,在下面的代码中 gcc
没有警告我有关索引的信息。这是什么原因?
int foo[3] = {1,2,3};
int (*bar)[3];
int main(void) {
bar = &foo;
foo[42] = 42;
(*bar)[42] = 42;
return 0;
}
我只得到 foo
的错误,bar
没有。为什么?
$ gcc -std=c99 -Wall -O2 -Wpedantic -Wextra test.c
test.c: In function ‘main’:
test.c:6:8: warning: array subscript is above array bounds [-Warray-bounds]
foo[42] = NOPE;
^
备注
我本可以编写 bar = foo
并将 bar
声明为 int* bar
,但我没有,我也不知道为什么...一种解决方案比另一种更好,这是另一个有趣的问题。
指针不携带大小信息,因此编译器无法检测越界访问。
GCC 似乎不保留和使用指向数组的指针的大小信息,即使它会在 bar=&foo
处抱怨不兼容的类型,如果您更改 bar
:
int foo[3] = {1,2,3};
int (*bar)[4];
int main(void) {
bar = &foo;
}
39893471.c: In function ‘main’:
39893471.c:5:9: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
bar = &foo;
^
我在 GCC 版本 4.8 和 6.1 上确认了此行为。
N.B。 -O2
参数是 -Warray-bounds
工作所必需的;这让我愣了一会儿!
经过一些实验,我意识到只有当两个数组索引相同时才会显示两个警告,即 foo 和 bar 均为 42。
如果将索引更改为不同的值,它似乎会显示所有警告。下面的 foo1 和 bar1 的定义与 foo 和 bar 完全相同。
bar = &foo;
bar1 = &foo1;
foo[10] = NOPE;
(*bar)[10] = NOPE;
(*bar1)[11] = NOPE;
foo1[12] = NOPE;
由于 bar 指向 foo,并且 gcc 已经对同一地址显示了警告,因此如果索引相同,则不会为 bar 显示相同的警告。反之亦然。在这里,警告显示的是 foo、bar1 和 foo1,而不是 bar。
希望这是一个合理的解释。
如果您评论 foo
访问权限,它会在 bar
访问权限上显示警告,所以这似乎只是 gcc
没有向您显示两次相同警告的情况。
它们是否应该被归类为相同的警告是另一回事 - 看看一方面有两个不同类型的变量,但另一方面它们为相同的内存起了别名。但这对我来说似乎很合理。最坏的情况是你进行额外的编译,直到你修复它们。
int foo[3] = {1,2,3};
int (*bar)[3];
int main()
{
bar = &foo;
// foo[42] = 42;
(*bar)[42] = 42; // warning
return 0;
}
20 : warning: array subscript is above array bounds [-Warray-bounds]
(*bar)[42] = 42;
~~~~~~~~~^
令我惊讶的是,在下面的代码中 gcc
没有警告我有关索引的信息。这是什么原因?
int foo[3] = {1,2,3};
int (*bar)[3];
int main(void) {
bar = &foo;
foo[42] = 42;
(*bar)[42] = 42;
return 0;
}
我只得到 foo
的错误,bar
没有。为什么?
$ gcc -std=c99 -Wall -O2 -Wpedantic -Wextra test.c
test.c: In function ‘main’:
test.c:6:8: warning: array subscript is above array bounds [-Warray-bounds]
foo[42] = NOPE;
^
备注
我本可以编写 bar = foo
并将 bar
声明为 int* bar
,但我没有,我也不知道为什么...一种解决方案比另一种更好,这是另一个有趣的问题。
指针不携带大小信息,因此编译器无法检测越界访问。
GCC 似乎不保留和使用指向数组的指针的大小信息,即使它会在 bar=&foo
处抱怨不兼容的类型,如果您更改 bar
:
int foo[3] = {1,2,3};
int (*bar)[4];
int main(void) {
bar = &foo;
}
39893471.c: In function ‘main’:
39893471.c:5:9: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
bar = &foo;
^
我在 GCC 版本 4.8 和 6.1 上确认了此行为。
N.B。 -O2
参数是 -Warray-bounds
工作所必需的;这让我愣了一会儿!
经过一些实验,我意识到只有当两个数组索引相同时才会显示两个警告,即 foo 和 bar 均为 42。 如果将索引更改为不同的值,它似乎会显示所有警告。下面的 foo1 和 bar1 的定义与 foo 和 bar 完全相同。
bar = &foo;
bar1 = &foo1;
foo[10] = NOPE;
(*bar)[10] = NOPE;
(*bar1)[11] = NOPE;
foo1[12] = NOPE;
由于 bar 指向 foo,并且 gcc 已经对同一地址显示了警告,因此如果索引相同,则不会为 bar 显示相同的警告。反之亦然。在这里,警告显示的是 foo、bar1 和 foo1,而不是 bar。
希望这是一个合理的解释。
如果您评论 foo
访问权限,它会在 bar
访问权限上显示警告,所以这似乎只是 gcc
没有向您显示两次相同警告的情况。
它们是否应该被归类为相同的警告是另一回事 - 看看一方面有两个不同类型的变量,但另一方面它们为相同的内存起了别名。但这对我来说似乎很合理。最坏的情况是你进行额外的编译,直到你修复它们。
int foo[3] = {1,2,3};
int (*bar)[3];
int main()
{
bar = &foo;
// foo[42] = 42;
(*bar)[42] = 42; // warning
return 0;
}
20 : warning: array subscript is above array bounds [-Warray-bounds]
(*bar)[42] = 42;
~~~~~~~~~^