Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 访问int(*foo)[3]的索引4时没有警告_C_Arrays_Gcc_Compiler Warnings - Fatal编程技术网

C 访问int(*foo)[3]的索引4时没有警告

C 访问int(*foo)[3]的索引4时没有警告,c,arrays,gcc,compiler-warnings,C,Arrays,Gcc,Compiler Warnings,在下面的代码中,我很惊讶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 fu

在下面的代码中,我很惊讶
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
中的元素数,它也会抱怨
bar=&foo
中的不兼容类型:

int foo[3] = {1,2,3};
int (*bar)[4];

int main(void) {
    bar = &foo;
}
39893471.c:在函数“main”中:
39893471.c:5:9:警告:来自不兼容指针类型的赋值[-Wincompatible指针类型]
bar=&foo;
^
我在GCC版本4.8和6.1上确认了这种行为


注意:
-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
访问进行评论,它会在
栏上显示警告,因此似乎这只是
gcc
没有两次显示相同警告的情况

它们是否应该被归类为相同的警告,这是另一回事——一方面,有两个不同类型的变量,但另一方面,它们别名相同的内存。但在我看来这很合理。最坏的情况是,在修复这两个问题之前,您需要进行额外的编译

int foo[3] = {1,2,3};
int (*bar)[3];

int main()
{
    bar = &foo;
    // foo[42] = 42;
    (*bar)[42] = 42; // warning
    return 0;
}


指针只是一个内存地址。不是某个高级对象知道它的边界和允许它接受的值。编译器无法知道您是否真的要指向foo[3]之后的下一个内存位置。也没有任何其他地点。您可以为指针指定任何想要的值。这也取决于你的名字,确定它指向的东西是有效的。clang 3.9.0在这里警告这两种情况。我认为这是一个编译器错误,因为
bar
是一个由3个指针组成的数组,正如
foo
是一个由3个
int
组成的数组一样s@MichaelWalz
bar
是指向3个
int
数组的指针,不是3个指针的数组。错误,
bar
是3个指针的数组。顺便说一句,Clang3.9.0警告了这两种情况。@MichaelWalz你说得对,我的C语言知识有点生疏,我误读了定义。但在这种情况下,你有没有线索,为什么GCC不能报告第二次越界访问?@米迦勒-<代码> bar <代码>是指向int数组[3 ]的指针。如果你不能读取声明,请考虑<代码> Bar=FoO < /Cord>,这将是你解释中的一个错误。gcc应该报告一个警告。如果访问权限是
bar[42]
,则您是对的。但事实上它是
(*bar)[24]
。它首先被解引用,然后被索引,被解引用的类型是
int[3]
,它携带大小信息@MichaelWalz gcc实际上会报告此案例的警告。在这里,它只是被第一次警告所隐藏。看看我的答案。别急着看虫子报告。看我的答案。你真的知道发生了什么。我只是把你的想法用一种更清晰更简单的方式改写了。
20 : warning: array subscript is above array bounds [-Warray-bounds]
(*bar)[42] = 42;
~~~~~~~~~^