关于C语言const变量能不能修改的问题

讨论一个轻松点的话题→

嵌入式开发面试中大家应该经常被问到在 C 语言中一个用 const 修饰的变量是否可以被修改,然后面试者回答:“可以”,面试官说:“你可以走了”。那么,恭喜你躲过一劫。好了,不开玩笑了。那如何回答关于 const 是否可以被修改的问题呢?我们直接动手试一下就知道了。

环境: Linux-4.9.151,gcc 7.5.0

  • 全局的初始化的 const 变量:
const int my_const = 10;

int main()
{
    return 0;
}

objdump -t 可以将目标文件中变量属于哪个段的内容打印出来:

objdump -t a.out | grep my_const
0000000000000694 g     O .rodata        0000000000000004              my_const

可以看到 my_const 在 rodata 段,因此这个变量无论如何都是不能被修改的。

  • 全局的未初始化的 const 变量:
const int my_const;

int main()
{
    return 0;
}

objdump -t 可以将目标文件中变量属于哪个段的内容打印出来:

objdump -t a.out | grep my_const
0000000000201014 g     O .bss   0000000000000004              my_const

可以看到未初始化的 my_const 在 bss 段,那么这个变量是否可以修改呢?我们先直接对其进行修改:

const int my_const;

int main()
{
    my_const = 2;
    return 0;
}

我们在使用 gcc 编译时发现 gcc 报错了:

gcc test.c
test.c: In function 'main':
test.c:7:14: error: assignment of read-only variable 'my_const'
     my_const = 2;
              ^

那有没有办法绕过 gcc 的检查呢?这是可以的,我们直接对其地址进行修改:

const int my_const;

int main()
{
    int *point = (int *)&my_const;
    *point = 2;
    printf("my_const is %d\n", my_const);
    return 0;
}
./a.out
my_const is 2

可以看到对全局未初始化的 const 变量地址进行操作,完全可以重写 const 变量中的内容。

  • 局部的未初始化/初始化的 const 变量:
int main()
{
    const int my_const0 = 1;
    const int my_const1;
    return 0;
}

通过 objdump 我们找不到 my_const0 和 my_const1,他们既不在 rodata 段也不在 bss 段。

但是我们通过对比发现,当定义这两个局部 const 变量后,text 段的大小变大了,也就是说这两个变量在 text 段中,当然这个说法不完全正确,应该说在函数运行时,局部变量会被压入栈,所以上述的 const 变量是在栈中被修改的。

那么我们试着通过地址对其进行修改:

int main()
{
    const int my_const0 = 1;
    const int my_const1;

    int *point = (int *)&my_const0;
    *point = 2;
    point = (int *)&my_const1;
    *point = 3;
    printf("my_const0 is %d, my_const1 is %d\n", my_const0, my_const1);
    return 0;
}
./a.out
my_const0 is 2, my_const1 is 3

我们看到这两个局部的初始化和未初始化的 const 的变量都是可以被修改的。

所以我们总结一下:

  • 全局初始化的 const 变量不能被修改;
  • 未初始化的 const 变量和局部 const 变量可以被修改,但必须通过地址对其进行修改;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小虾米的Daddy

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值