为什么 const int main = 195 导致一个工作程序但没有 const 它以分段错误结束?
Why does const int main = 195 result in a working program but without the const it ends in a segmentation fault?
考虑以下 C 程序(查看现场演示 here)。
const int main = 195;
我知道在现实世界中没有程序员会写这样的代码,因为它没有任何用处,也没有任何意义。但是,当我从程序上方删除 const
关键字时,它会立即导致 segmentation fault。为什么?我很想知道这背后的原因。
GCC 4.8.2 在编译时给出以下警告。
warning: 'main' is usually a function [-Wmain]
const int main = 195;
^
为什么 const
关键字的存在和不存在会影响程序的行为?
在 C 中,main
在全局范围内几乎总是一个函数。
在全局范围内使用 main
作为变量会使程序的行为不确定。
(只是 可能 是这种情况,当您编写 const
时,编译器会将变量优化为常量,因此您的程序行为会有所不同。但是程序行为仍然未定义)。
观察值 195 如何对应于 8086 兼容机上的 ret
(return 来自函数)指令。 main
的这个定义因此在执行时就像您将其定义为 int main() {}
一样。
在某些平台上,const
数据被加载到可执行但不可写的内存区域,而可变数据(即不合格的数据 const
)被加载到可写但不可执行的内存区域。出于这个原因,当您将 main
声明为 const
时该程序“有效”,但当您不使用 const
限定符时则无效。
传统上,二进制文件包含三个 段:
text
段是(如果架构支持的话)写保护和可执行的,包含可执行代码,static存储期限合格的变量const
, 和字符串文字
data
段是可写的,不能执行。它包含未限定 const
且具有 static 存储持续时间的变量和(在运行时)具有 allocated 存储持续时间 的对象
bss
段与 data
段类似,但初始化为全零。它包含 static 存储持续时间未限定 const
的变量,这些变量已在没有初始化程序的情况下声明
- 二进制文件中不存在
stack
段,并且包含具有 自动 存储持续时间的变量
从变量 main
中删除 const
限定符会导致它从 text
移动到 data
段,该段不可执行,从而导致您观察到的分段违规。
现代平台通常有更多的段(例如 rodata
段用于既不可写也不可执行的数据)因此请不要在未查阅平台特定文档的情况下将其视为对您的平台的准确描述。
请理解,不将 main
设为函数通常是不正确的,尽管从技术上讲,平台可以允许将 main
声明为变量,请参见。 ISO 9899:2011 §5.1.2.2.1 ¶1,强调我的:
1 The function called at program startup is named main
. The implementation declares no prototype for this function. It shall be defined with a return type of int
and with no parameters (...) or with two parameters (...) or equivalent; or in some other implementation-defined manner.
考虑以下 C 程序(查看现场演示 here)。
const int main = 195;
我知道在现实世界中没有程序员会写这样的代码,因为它没有任何用处,也没有任何意义。但是,当我从程序上方删除 const
关键字时,它会立即导致 segmentation fault。为什么?我很想知道这背后的原因。
GCC 4.8.2 在编译时给出以下警告。
warning: 'main' is usually a function [-Wmain]
const int main = 195; ^
为什么 const
关键字的存在和不存在会影响程序的行为?
在 C 中,main
在全局范围内几乎总是一个函数。
在全局范围内使用 main
作为变量会使程序的行为不确定。
(只是 可能 是这种情况,当您编写 const
时,编译器会将变量优化为常量,因此您的程序行为会有所不同。但是程序行为仍然未定义)。
观察值 195 如何对应于 8086 兼容机上的 ret
(return 来自函数)指令。 main
的这个定义因此在执行时就像您将其定义为 int main() {}
一样。
在某些平台上,const
数据被加载到可执行但不可写的内存区域,而可变数据(即不合格的数据 const
)被加载到可写但不可执行的内存区域。出于这个原因,当您将 main
声明为 const
时该程序“有效”,但当您不使用 const
限定符时则无效。
传统上,二进制文件包含三个 段:
text
段是(如果架构支持的话)写保护和可执行的,包含可执行代码,static存储期限合格的变量const
, 和字符串文字data
段是可写的,不能执行。它包含未限定const
且具有 static 存储持续时间的变量和(在运行时)具有 allocated 存储持续时间 的对象
bss
段与data
段类似,但初始化为全零。它包含 static 存储持续时间未限定const
的变量,这些变量已在没有初始化程序的情况下声明- 二进制文件中不存在
stack
段,并且包含具有 自动 存储持续时间的变量
从变量 main
中删除 const
限定符会导致它从 text
移动到 data
段,该段不可执行,从而导致您观察到的分段违规。
现代平台通常有更多的段(例如 rodata
段用于既不可写也不可执行的数据)因此请不要在未查阅平台特定文档的情况下将其视为对您的平台的准确描述。
请理解,不将 main
设为函数通常是不正确的,尽管从技术上讲,平台可以允许将 main
声明为变量,请参见。 ISO 9899:2011 §5.1.2.2.1 ¶1,强调我的:
1 The function called at program startup is named
main
. The implementation declares no prototype for this function. It shall be defined with a return type ofint
and with no parameters (...) or with two parameters (...) or equivalent; or in some other implementation-defined manner.