通过GDB分析字符串不能修改的原因

在学习C、C++的过程中,或多或少多接触过:字符串内容不能修改。一般告知的原因是字符串存放在字符常量区,字符常量区的内容不能修改。

细心的同学会发现,如果一个字符串数组中存放的数据也是放在字符常量区的,为什么数组的内容可以修改?

基于这个问题,写出了如下测试代码。

#include <iostream>
using namespace std;

int main()
{

    char *p = "hello world";
    char str[] = "doanld";

    str[0] = 'D';
    p[0] = 'H'; //运行出错,会提示 bus error

    printf("p[0] = %c, *p = %s, str = %s\n", p[0], p, str);
}

有了上面的代码,编译得到的文件使用ida反编译,可以看到汇编代码,其中的
"hello world"保存在 aHelloWorld中,"doanld"保存在cs:aDoanld中,
在这里插入图片描述
定位后发现 aHelloWorldcs:aDoanld在__cstring区块中,同时文中用到的print字段也在其中。
在这里插入图片描述

通过此就可以看出,所有的字符串都存放在__cstring section中。即,代码中定义的C字符串存放在__cstring节中。该字段的字符不能修改。

因为char *p = "hello world";p指向aHelloWorld,所以不能修改,从汇编层面也能看出,对应的汇编代码为lea rax, aHelloWorld ;中用的lea

为什么数组中可以修改字符串的值?实际,数组中是存放了一份字符串的拷贝(存放在栈上),修改的是栈上的拷贝,从汇编春光也能看出。

对应的汇编代码为:

mov     [rbp+var_8], rax
mov     edx, dword ptr cs:aDoanld ; "doanld"
mov     [rbp+var_F], edx
mov     si, word ptr cs:aDoanld+4 ; "ld"

其他

  • 上面代码,在编译的时候,在char *p = "hello world"处会有“conversion from string literal to 'char *' is deprecated”警告,该警告的解决办法是,加上const,即:const char *p = "hello world"; 通过这种方式来理解p所指向的内容不能修改就更加容易了。

  • lea指令
    load effective address, 加载有效地址,可以将有效地址传送到指定的的寄存器。指令形式是从存储器读数据到寄存器, 效果是将存储器的有效地址写入到目的操作数, 简单说, 就是C语言中的”&”.

  • mov指令
    在CPU内或CPU和存储器之间传送字或字节。

    • lea 和 mov使用区别
      • lea对变量没有影响是取地址
      • mov对变量来说没有影响是取值
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值