第一个文件:
//a.c
const int i = 9; //Just contains the variable definition
Run Code Online (Sandbox Code Playgroud)
第二个文件:
//b.c
#include<stdio.h>
extern int i;
int main()
{
int *ptr = &i;
printf("Before: %d\n",i);
*ptr = 99;
printf("After: %d\n",i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我原本期望在bc中const出现限定符错误/警告extern int i;和只读内存修改错误,但编译却进展顺利。*ptr = 99;
第一个打印语句打印良好,但第二个打印语句出现分段错误。
为什么它没有在编译阶段崩溃并出现预期的错误,而是给出分段错误?
注意 - GCC 8.3.0
const int根据标准,尝试通过指针写入是未定义的行为。
实践中可能发生的情况是,您的变量被放置在可执行文件的.rodata区域中 - 该区域在内存中标记为只读 - 当您尝试通过指针写入它时,它会触发页面错误,导致程序崩溃。
const如果您需要写入变量,则删除应该可以解决此问题。
翻译单元单独编译。因此编译器不知道它i在const其他文件中。它信任以下声明:
extern int i;\nRun Code Online (Sandbox Code Playgroud)\n那里没有const。这就是为什么您看不到任何警告。
为了确保尽早检测到类似的错误,建议将全局变量的声明放入头文件中,并让两者a.c都b.c包含此头文件。
在这种情况下,编译器将在编译时生成诊断信息a.c,因为声明和定义不兼容。
... a.h\n#pragma once\nextern int i;\n\n... a.c\n#include "a.h"\nconst int i = 9;\n\n... b.c\n#include<stdio.h>\n#include "a.h"\n\nint main()\n{\n int *ptr = &i;\n\n printf("Before: %d\\n",i);\n\n *ptr = 99;\n\n printf("After: %d\\n",i);\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n编译命令:
\ngcc a.c b.c\nRun Code Online (Sandbox Code Playgroud)\n错误:
\na.c:3:11: error: conflicting type qualifiers for \xe2\x80\x98i\xe2\x80\x99\n 3 | const int i = 9;\n | ^\nIn file included from a.c:1:\na.h:2:12: note: previous declaration of \xe2\x80\x98i\xe2\x80\x99 was here\n 2 | extern int i;\n | ^\n\nRun Code Online (Sandbox Code Playgroud)\n编辑
\n编译时,a.c编译器假设该对象是常量,并将其放入只读内存中。在 Linux 机器上,它将被放置.rodata在没有标志的情况下映射到进程地址空间的部分PROT_WRITE。
当内存被修改时b.c会引发分段错误异常(对内存的无效访问)并且程序崩溃。
请注意,修改常量对象会触发未定义的行为。该程序可能会运行数年,然后突然开始崩溃。
\n