请参阅下一个代码和结果:
foo.c的:
const int extern_const = 1;
的main.c
#include <stdio.h>
extern int extern_const;
int main(void)
{
printf("before: %d\n", extern_const);
extern_const = 2;
printf("after : %d\n", extern_const);
return 0;
}
编译和结果:
$ gcc -shared -fpic foo.c -o libfoo.so
$ gcc main.c -L. -lfoo -o test
$ LD_LIBRARY_PATH=`pwd` ./test
before: 1
after : 2
我声明了一个const int变量extern_const
,它驻留在一个共享库libfoo.so
中。
在main.c中,我将extern_const声明为extern int
而不是extern const int
,并将值从1更改为2. 这是否安全有效?
执行结果显示替换仍然有效。我听说覆盖const值会引发未定义的行为,实际上,当我一次编译foo.c和main.c(没有创建共享库)时,程序实际上在第二次printf之前以分段错误结束。
我想知道的是接下来的事情:
答案 0 :(得分:5)
修改常量对象是未定义的行为。任何事情都可能发生。
在你的情况下,你可能已经变得不幸因为GCC还没有汇集所有常量变量和文字,它没有将它放入只读部分(定义更多它们并且可能发生),你的main()
是访问该外部常量对象的第一个也是最后一个代码(虽然在假旗下作为非const)。
6.7.3类型限定符§6
如果尝试通过use修改使用const限定类型定义的对象 如果是非const限定类型的左值,则行为未定义。如果是尝试 通过使用左值来引用用volatile限定类型定义的对象 对于非volatile限定类型,行为未定义.133)
答案 1 :(得分:3)
基本上,它由编译器/工具链/操作系统来提供对const变量的保护。这些的一些组合尽可能地确保那些应该只读的内容是只读的,即使它意味着分配整个页面(几KB)只是为了存储一个变量。其他人做出了不同的权衡,并且不会为了保护一个变量而浪费大量空间,并且信任程序员不要做这样的疯狂事情。
答案 2 :(得分:1)
其他答案绝对正确,因为这是未定义的行为,因此你不应该这样做。您的代码破解为您“工作”的原因是动态链接工作方式的副作用,即复制重定位。基本上,所发生的是,由于主可执行文件不是与位置无关的,因此它必须具有其访问的所有数据对象的地址,该地址直接硬编码为执行访问的指令中的即时可执行文件。因此,链接器在主程序的可写数据段中分配可写空间(因为在运行时来自共享库的值),并且包含对动态链接器的指令,以便从中复制值。在启动时执行重定位时,共享库到主程序的数据。然后,修补共享库中的任何引用,以指向主程序数据中的新副本。
如果您希望看到代码失败,请尝试将主程序编译为与位置无关的可执行文件:
$ gcc -fPIE -pie main.c -L. -lfoo -o test
看看会发生什么。请注意,PIE在许多强化系统上是默认的。同样,某些cpu架构的ABI(MIPS是一个,如果我没有弄错的话)从不需要复制重定位,因此即使没有PIE,你的程序也会崩溃。
答案 3 :(得分:0)
在foo.c中,添加:
int y;
void f(void) {
y = extern_const;
}
编译foo.c并优化程序集。阅读f()
的程序集。如果您的编译器与我的一样,您应该看到f()
已经优化到相当于y = 1;
这意味着根据我的编译器(可能是你的编译器),你所做的并不合适,并且你应该得到任何奇怪的恶魔,因为在不同的文件中以不同的方式声明extern_const
而可能会飞出你的鼻子
答案 4 :(得分:0)
您的示例违反了一个定义规则。这是未定义的行为,因此在编译阶段可能会发生任何,并且您的程序无法保证做任何有用的事情,另请参阅here。
J.2未定义的行为
同一对象或函数的两个声明指定不兼容的类型 (6.2.7)。
也
6.2.7兼容类型和复合类型
2所有引用同一对象或函数的声明都应具有兼容的类型; 否则,行为未定义。
也
6.7.3类型限定符
10对于两种兼容的合格类型,两者都应具有相同的合格版本 兼容类型;说明符或限定符列表中类型限定符的顺序 不会影响指定的类型。
此外,正如其他人所说,修改const对象也是未定义的行为:
6.7.3类型限定符
6如果尝试通过use修改使用const限定类型定义的对象 如果是非const限定类型的左值,则行为未定义。如果是尝试 通过使用左值来引用用volatile限定类型定义的对象 对于非volatile限定类型,行为未定义.133)