C语言 const变量能不能修改?

 笔者在跟同事讨论变量存放的分区问题时,讨论到了const标识符所标记的变量能不能修改这个问题。

按直观理解,const关键字标识的变量,意味不能修改的变量,引申理解,猜测其可能存放在.rodata分区(只读)。

C语言 const变量能不能修改?_第1张图片

========================================================================

来实际操作验证一下,一看便知。

环境:选用Ubuntu平台,x86 gcc工具。

一、局部的const变量

代码验证:首先是局部的const变量

#include 
#include 

//const int global_const_vol = 84;
char *s = "abcde";
int main()
{
        const int const_vol = 11; 

        return 0;
}

C语言的字符串变量会放在rodata段,我们以此作为参考

gcc -c选项可以只将.c文件编译成目标文件(.o),而不进行链接,使我们分析自己写的代码少了很多冗余代码,方便分析。

objdump -xsd 可以将目标文件中各个段的内容都打印出来。

C语言 const变量能不能修改?_第2张图片

 我们只需要找我们定义的两个变量就好了,const_vol,s。

可以看到.data段中啥也没有,我们的s变量被放在了rodata段,存放的就是我们初始化的abcde变量,而const变量不知道去哪里了。

 答案是在.text段(代码段)里,对比以下代码和dump结果便知。

include 
#include 

//const int global_const_vol = 84; 
char *s = "abcde";
int main()
{
//        const int const_vol = 11; 

        return 0;
}

 编译 && dump

C语言 const变量能不能修改?_第3张图片

 很明显,.text段中的c745fc0b这块数据丢了。

C语言 const变量能不能修改?_第4张图片

并且.data段的大小没变化

我们可以得出结论:本环境下的局部const变量存放于text段中,程序运行时会将此变量放置于栈区。

既然在栈中,那其本身就应该处于可以修改的内存位置

我们先直接对其进行修改。

int main()
{
        const int const_vol = 11;

        const_vol = 100;

        printf("const_vol = %d\n",const_vol);
        return 0;
}

 编译

 报错,那显然不能执行了。

直接对其地址进行修改呢?

int main()
{
        const int const_vol = 11; 
        int *pointer = &const_vol;
            
        *pointer = 100;

        printf("const_vol = %d\n",const_vol);
        return 0;
}

编译器只进行了警告,我们的const变量也成功被改写了;

结论:对局部的const变量地址进行操作,完全可以重写const变量中的内容;

二、全局的const变量

首先第一个问题,全局const变量存放的位置。

代码:

const int global_const_vol = 10; 
char *s = "abcde";
int main()
{
        return 0;
}

 编译成.o文件,并ojbdump:

 C语言 const变量能不能修改?_第5张图片

 可以看到rodata中除了abcde以外,多了0a000000。

C语言 const变量能不能修改?_第6张图片

这是由于是小端字节序的文件,正确的顺序应该是0000000a,即10,我们的全局const变量。

得出结论:全局const变量是存放于rodata区的。

那能否进行修改呢?

const int global_const_vol = 10; 
char *s = "abcde";
int main()
{
        int *pointer = &global_const_vol;
           
        *pointer = 100;

        printf("global_const_vol = %d\n",global_const_vol);
        return 0;
}

 

 编译只有warning,和局部的const变量一样

 但执行就报段错误了,因为我们修改的是rodata段的变量。

结论:全局const变量是存放于rodata区的,无论如何都不能修改。

总结 

在gcc工具链中,局部const变量不能直接修改是由编译器控制的,其本身存放于代码运行时,临时分配的函数栈中。

而全局的const变量存放于rodata分区,任何时候都是只读变量。

你可能感兴趣的:(C语言基础,c语言,内存结构)