美文网首页互联网科技嵌入式编程
字符串在程序的哪里?

字符串在程序的哪里?

作者: 罗蓁蓁 | 来源:发表于2020-05-01 12:15 被阅读0次

这一篇分析字符串,字符串经常被使用,但是它的秘密也不少:

一、字符串的存储位置

C源程序(string1.c):

#include <stdio.h>
int main()
{
    puts("Hello, World!");
    return 0;
}

我们直接看可执行文件的反汇编结果:

[lqy@localhost temp]$ gcc -o string1 string1.c
[lqy@localhost temp]$ ./string1 
Hello, World!
[lqy@localhost temp]$ objdump -s -d string1 > string1.txt
[lqy@localhost temp]$ 

string1.txt 中的部分内容如下:

Contents of section .rodata:
 8048488 03000000 01000200 00000000 48656c6c  ............Hell
 8048498 6f2c2057 6f726c64 2100               o, World!.  
...
080483b4 <main>:

 80483b4:   55                      push   %ebp
 80483b5:   89 e5                   mov    %esp,%ebp
 80483b7:   83 e4 f0                and    $0xfffffff0,%esp
 80483ba:   83 ec 10                sub    $0x10,%esp
 80483bd:   c7 04 24 94 84 04 08    movl   $0x8048494,(%esp)
 80483c4:   e8 27 ff ff ff          call   80482f0 puts@plt
 80483c9:   b8 00 00 00 00          mov    $0x0,%eax
 80483ce:   c9                      leave
 80483cf:   c3                      ret

可见 0x8048494 应该是 "Hello, World!" 的地址,然后发现在 .rodata 段中 0x8048488 + 12 处正好存储着 "Hello, World!" 的各个字符的ASCII码:'H' 的 <a target="_blank" href="http://www.asciitable.com/">ASCII码</a>是 0x48,而感叹号 '!' 的 <a target="_blank" href="http://www.asciitable.com/">ASCII码</a> 码是 0x21,最后编译器还自动的为我们添了个字符串结束符 0x00:只要是双引号括起来的字符串,编译器都会自动的为我们加结束符。

由此我们发现:

字符串和全局变量一样做为静态数据存储在可执行文件中,在使用的时候用常量地址来访问。

但是字符串被放在了 .rodata 段中,这个段中的数据与 .text 段(代码段)中的数据一样在可执行文件被载入内存运行时都是只读的(这里的只读是通过分页管理实现的:在页表表项中有一个位,设置为 1 表示该页可写,设置为 0 表示该页只读;如果试图向只读的页中写入数据,CPU 就会触发页保护异常)。

所以源字符串中的任何字符都不能在程序运行时更改。

二、字符串指针 和 字符数组

C源程序(string2.c):

#include <stdio.h>
int main()
{
    char *s1 = "1234567";
    char s2[]= "1234567";
    
    puts(s1);
    puts(s2);
    return 0;
}

可执行文件的反汇编结果的赋值部分如下:

 80483bd:   c7 44 24 1c c4 84 04    movl   $0x80484c4,0x1c(%esp)
 80483c4:   08 
 80483c5:   a1 c4 84 04 08          mov    0x80484c4,%eax
 80483ca:   8b 15 c8 84 04 08       mov    0x80484c8,%edx
 80483d0:   89 44 24 14             mov    %eax,0x14(%esp)
 80483d4:   89 54 24 18             mov    %edx,0x18(%esp)

0x80484c4 是字符串"1234567"的地址,所以:常量字符串赋值给指针时传递的是源字符串的地址;而赋值给局部字符数组时,要当成数字一个个拷贝到局部变量空间。因此第2种方式既浪费空间(4字节 vs 8字节)又浪费时间(1个mov vs 4个mov)。

但是第2种方式也不是一无是处:第1种方式传递的是源字符串的地址,而源字符串在只读页中,无法修改,但是字符数组却可以修改。

经验:如果程序中本来就没想改动该字符串,那就用指针吧;否则用 字符数组 或 动态申请的空间 来存。

三、格式描述符 和 转义符

这个部分,我们来看看字符串中格式描述符和转义符的来龙去脉,C源程序(string3.c):

#include <stdio.h>
int main()
{
    printf("--------\n%d\n", 123);
    return 0;
}
汇编源文件中
gcc -S string3.c

结果如下:

.LC0:
    .string "--------\n%d\n"
目标文件中
gcc -c string3.c
objdump -s -d string3.o > string3.txt

-c 默认输出到 string3.o 文件中,string3.txt 中的字符串:

Contents of section .rodata:
 0000 2d2d2d2d 2d2d2d2d 0a25640a 00        --------.%d..   

两个'\n'被替换成了 0x0a,%d 没变

可执行文件中
gcc -o string3 string3.c
objdump -s -d string3 > string3.txt

可执行文件跟目标文件一样:

Contents of section .rodata:
 80484a8 03000000 01000200 00000000 2d2d2d2d  ............----
 80484b8 2d2d2d2d 0a25640a 00                 ----.%d..       

所以我们知道了:转义符在变成二进制文件后就被转义为我们想表达的那个字符了,而格式描述符自然是要留给 printf 运行时用的

知道这个有什么用?如果我们来设计 printf 函数,那么转义字符我们就不用操心了,编译器会把它们转义过去的。

出差必备

买火车票、高铁票、机票,订酒店都打9折的出行工具TRIP,点击注册

相关文章

  • 字符串在程序的哪里?

    这一篇分析字符串,字符串经常被使用,但是它的秘密也不少: 一、字符串的存储位置 C源程序(string1.c): ...

  • 08.包装类的概述和基本使用

    包装类 在实际程序使用中,程序界面上用户输入的数据都是以字符串类型进行存储的。而程序开发中,我们需要把字符串数据,...

  • 字符串(四)

    字符串常用函数 在程序开发中,字符串经常需要被处理,例如求字符串的长度、大小写转换等。如果每次处理字符串时,都编写...

  • DotNet Core Web API 项目搭建和部署

    数据库连接字符串 在文件appsettings.json中添加连接字符串 将程序部署到Windows server...

  • 【编测编学】零基础学python_04_字符串(删除空白)

    删除字符串中的空白: 在程序中,额外的空白可能令人迷惑。对程序员来说,'python' 和'python ' 看起...

  • 【习题46】

    【程序46】题目:两个字符串连接程序

  • 【习题40】

    【程序40】题目:字符串排序。

  • asp.net core 系列 22 EF(连接字符串,连接复原

    一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices...

  • TextUtils

    常用的几个:拼接字符串,判断字符串相等,是否为空 说个不常用的 ellipsize 首先这个东西哪里用到了?在自定...

  • Java 中的字符串是什么

    什么是 Java 中的字符串 在程序开发中字符串无处不在,如用户登陆时输入的用户名、密码等使用的就是字符串。其实,...

网友评论

    本文标题:字符串在程序的哪里?

    本文链接:https://www.haomeiwen.com/subject/sgofghtx.html