声明为“const”的全局初始化变量转到文本段,而声明为“Static”的全局初始化变量转到数据段。 为什么?

#include  const int str[1000] = {0}; int main(void) { printf("arr is %d\n", str[0]); return 0; } 

有以下输出:

 [-exercises/adam/stack2]:size a.out text data bss dec hex filename 5133 272 24 5429 1535 a.out 

鉴于:

 #include  static int str[1000] = {0}; int main(void) { printf("arr is %d\n", str[0]); return 0; } 

有以下输出:

 [-exercises/adam/stack2]:size a.out text data bss dec hex filename 1080 4292 24 5396 1514 a.out 

当数组未初始化时 – 它再次进入“const”的文本段和“静态”的BSS。

变量是全局变量,应该可以从可执行文件中的任何位置访问(因为没有“静态”),但是考虑到它的变量,我不知道它为什么放在文本段而不是数据段?

你很困惑。 conststatic之间没有二分法; 这两个是独立的。 假设所有数据都已初始化, static const和外部(全局) const都将进入text ,非const -qualified static和non const -qualified external将进入data

至于bss ,像ELF这样的现代二进制格式实际上对于常量和非常量零数据具有单独的bsssize命令的输出不显示它。

来自Kernighan&Ritchie

static是存储类说明符。 其他存储类说明符是:auto,register,extern和typedef。 静态说明符为声明的对象提供静态存储类。 应用于外部变量或函数的静态声明将该对象的范围限制为正在编译的源文件的其余部分。 静态对象可以是块的本地对象,也可以是所有块的外部对象,但在任何一种情况下,都可以在退出和重新进入函数和块的过程中保留它们的值。

然而,

const是一个类型限定符。 另一种类型限定符是volatile。 const的目的是宣布可能放在只读存储器中的对象,并且可能增加优化的机会。

我想可以推断这两个关键字都有不同的用途; const变量在text/code segment中的含义非常清楚。

允许内存保护工作。 任何写入const的尝试都会触发段错误。

当你声明一个变量const你告诉编译器你永远不打算改变它的值。 另一方面,通过在文件范围内进行static声明,您告诉编译器该变量对于已声明的编译单元是私有的,但仍允许该编译单元中的函数修改此变量。

正如Oli在他的回答中提到的,在text段中定位const变量允许系统强制执行内存访问保护。 此外,考虑一个嵌入式系统,在这种情况下, text段通常写入闪存,因此是不可修改的。 databss段等位于RAM中,允许进行修改。

通过将const数据放入文本部分,编译器正在尝试强制执行constness。

请记住,TEXT部分被加载到MMU页表中标记为只读的内存页面中。 这是为了防止代码意外损坏。 通过将const数据放在同一区域中,也可以只读取该数据。 然后,对此数据的任何写入都将调用exception。

声明为static的未初始化数据将进入BSS段以节省可执行文件中的空间。 该区域由加载器分配在内存中。 声明为static的初始化数据将进入DATA段,这是读写的。