c - 为什么未初始化而不是越界?
问题描述
在下面的代码中,为什么b[9]
未初始化而不是越界?
#include <stdio.h>
int main(void)
{
char b[] = {'N', 'i', 'c', 'e', ' ', 'y', 'o', 'u', '!'};
printf("b[9] = %d\n", b[9]);
return 0;
}
编译器调用:
% gcc -O2 -W -Wall -pedantic -c foo.c
foo.c: In function ‘main’:
foo.c:6:5: warning: ‘b[9]’ is used uninitialized in this function [-Wuninitialized]
printf("b[9] = %d\n", b[9]);
% gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.6) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
更新:现在这很奇怪:
#include <stdio.h>
void foo(char *);
int main(void)
{
char b[] = {'N', 'i', 'c', 'e', ' ', 'y', 'o', 'u', '!'};
foo(&b[9]);
foo(&b[10]);
printf("b[9] = %d\n", b[9]);
printf("b[10] = %d\n", b[10]);
return 0;
}
编译它会导致人们期望的警告:
% gcc -O2 -W -Wall -pedantic -c foo.c
foo.c: In function ‘main’:
foo.c:9:5: warning: array subscript is above array bounds [-Warray-bounds]
foo(&b[10]);
^
foo.c:10:29: warning: array subscript is above array bounds [-Warray-bounds]
printf("b[9] = %d\n", b[9]);
^
foo.c:11:29: warning: array subscript is above array bounds [-Warray-bounds]
printf("b[10] = %d\n", b[10]);
突然 gcc 看到了它的界限。
解决方案
我相信这里可能是这种情况:在第一个代码中,GCC 注意到您根本不需要整个 char 数组,只需b[9]
,因此它可以将代码替换为
char b_9; // = ???
printf("b[9] = %d\n", b_9);
现在,这是一个完全合法的转换,因为当数组被越界访问时,行为完全是 undefined。只有在后期阶段,它才会注意到这个替代 的变量b[9]
未初始化,并发出诊断消息。
为什么我相信这个?因为如果我只添加任何将引用内存中数组地址的代码,例如printf("%p\n", &b[8]);
在任何地方,数组现在完全在内存中实现,编译器将诊断数组下标是否高于数组边界。
我发现更有趣的是,除非启用优化,否则 GCC 根本不会诊断越界访问。这再次表明,每当您编写程序新程序时,您应该在启用优化的情况下编译它,以使错误高度可见,而不是在调试模式下隐藏它们;)
推荐阅读
- python - Django - 尝试将对象转换为 Json 时,select_related 不显示表格
- javascript - 将对象推入数组中,而无需在 javascript 中使用键
- android - gitlab runner npm install 错误“npm ERR!prepareGitDep”
- deep-learning - 关于使用 1*1 卷积的技巧
- python-3.x - 这段代码可能有什么问题?我收到“未定义 gs”错误
- apache - 如何使用 .htaccess 将 URL 重定向到新 URL?
- python - 在 Pandas 数据框中查找最接近输入的值
- java - 具有自动生成的主键并能够手动设置 JPA
- marklogic - Gradle 和代理:协商身份验证错误:提供的名称无效(机制级别:KrbException:找不到默认领域)
- c++ - E2140 表达式必须具有整数或无范围枚举类型