考虑以下C程序(参见这里的实时演示)。
const int main = 195;
我知道在现实世界中没有程序员写这样的代码,因为它没有任何有用的目的,没有任何意义。但是,当我从上面的程序中删除const
关键字时,它立即导致分割错误。为什么?我很想知道这背后的原因。
GCC 4.8.2在编译时给出如下警告:
警告:'main'通常是一个函数[-Wmain]
const int main = 195; ^
为什么const
关键字的存在和不存在会对程序的行为产生影响?
观察值195如何对应于8086兼容设备上的ret
(从函数返回)指令。因此,main
的定义在执行时的行为就像您将其定义为int main() {}
一样。
在某些平台上,const
数据被加载到可执行但不可写的内存区域,而可变数据(即不符合const
的数据)被加载到可写但不可执行的内存区域。由于这个原因,当您将main
声明为const
时,程序"工作",但当您放弃const
限定符时,程序就不工作了。
传统上,二进制文件包含三个段:
-
text
段(如果体系结构支持)是写保护的,可执行的,包含可执行代码,静态存储持续时间合格的const
变量和字符串字量 -
data
段是可写的,不能执行。它包含不具有静态存储持续时间的const
变量和(在运行时)具有分配存储持续时间 的对象。 -
bss
段与data
段相似,但初始化为全零。它包含静态存储持续时间不符合const
的变量,这些变量在没有初始化式 的情况下声明。 -
stack
段不存在于二进制文件中,并且包含具有自动存储持续时间 的变量
从变量main
中删除const
限定符会导致它从text
段移动到data
段,这是不可执行的,导致您观察到的分段冲突。
现代平台通常有进一步的段(例如,rodata
段用于既不可写也不可执行的数据),所以在没有参考平台特定文档的情况下,请不要将其视为对平台的准确描述。
请理解,不将main
作为函数通常是不正确的,尽管从技术上讲,平台可以允许将main
声明为变量,参见ISO 9899:2011§5.1.2.2.1¶1,强调我:
1程序启动时调用的函数命名为
main
。实现没有为这个函数声明原型。它应该定义为返回类型int
,不带参数(…),或者带两个参数(…),或者是等价的;或者以其他实现定义的方式
在C语言中,main
在全局作用域中几乎总是一个函数。
在全局作用域中使用main
作为变量会使程序的行为未定义。
(它只是可能是这样的情况,当您编写const
时,编译器将变量优化为常量,因此您的程序行为不同。但是程序行为是仍然 undefined)。