网站地图用什么格式,个人博客网页,购物商城外贸网站,深圳市房地产交易中心官网相关阅读
C语言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm1001.2014.3001.5482 虽然C语言中不存在字符串类型#xff0c;但依然可以通过数组或指针的方式保存字符串#xff0c;但字符串字面量却没有想象的这么简单#xff0c;本文就将对此进行讨论…相关阅读
C语言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm1001.2014.3001.5482 虽然C语言中不存在字符串类型但依然可以通过数组或指针的方式保存字符串但字符串字面量却没有想象的这么简单本文就将对此进行讨论。 字符串字面量保存在静态存储区所谓静态存储区即表示其值在程序执行前就已存在于可执行文件中。如果更详细地说字符串字面量可能保存在.rodata section中所以当尝试使用指针改变一个字符串字面量的值时会出现段错误。需要特别说明的是上面所说的字符串字面量的位置没有任何限制可以是在函数内也可以是在函数外如下面的代码所示。
例1
#include stdio.h
char *ptr1 abcde; //abcde被添加到.rodata section
int main()
{char *ptr2 ABCDE; //ABCDE被添加到.rodata sectionprintf(This is a string); //This is a string被添加到.rodata section
} 现在我们可以使用gcc编译链接成可执行程序如下所示。
$gcc test.c -o test 然后使用readelf命令读取二进制可执行文件test中的信息注意这里添加了-S选项表示只输出section头的相关信息。
$readelf -S test
There are 31 section headers, starting at offset 0x36c0:Section Headers:[Nr] Name Type Address OffsetSize EntSize Flags Link Info Align[ 0] NULL 0000000000000000 000000000000000000000000 0000000000000000 0 0 0[ 1] .interp PROGBITS 0000000000000318 00000318000000000000001c 0000000000000000 A 0 0 1[ 2] .note.gnu.pr[...] NOTE 0000000000000338 000003380000000000000030 0000000000000000 A 0 0 8[ 3] .note.gnu.bu[...] NOTE 0000000000000368 000003680000000000000024 0000000000000000 A 0 0 4[ 4] .note.ABI-tag NOTE 000000000000038c 0000038c0000000000000020 0000000000000000 A 0 0 4[ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b00000000000000024 0000000000000000 A 6 0 8[ 6] .dynsym DYNSYM 00000000000003d8 000003d800000000000000a8 0000000000000018 A 7 1 8[ 7] .dynstr STRTAB 0000000000000480 00000480000000000000008f 0000000000000000 A 0 0 1[ 8] .gnu.version VERSYM 0000000000000510 00000510000000000000000e 0000000000000002 A 6 0 2[ 9] .gnu.version_r VERNEED 0000000000000520 000005200000000000000030 0000000000000000 A 7 1 8[10] .rela.dyn RELA 0000000000000550 0000055000000000000000d8 0000000000000018 A 6 0 8[11] .rela.plt RELA 0000000000000628 000006280000000000000018 0000000000000018 AI 6 24 8[12] .init PROGBITS 0000000000001000 00001000000000000000001b 0000000000000000 AX 0 0 4[13] .plt PROGBITS 0000000000001020 000010200000000000000020 0000000000000010 AX 0 0 16[14] .plt.got PROGBITS 0000000000001040 000010400000000000000010 0000000000000010 AX 0 0 16[15] .plt.sec PROGBITS 0000000000001050 000010500000000000000010 0000000000000010 AX 0 0 16[16] .text PROGBITS 0000000000001060 00001060000000000000011b 0000000000000000 AX 0 0 16[17] .fini PROGBITS 000000000000117c 0000117c000000000000000d 0000000000000000 AX 0 0 4[18] .rodata PROGBITS 0000000000002000 000020000000000000000021 0000000000000000 A 0 0 4[19] .eh_frame_hdr PROGBITS 0000000000002024 000020240000000000000034 0000000000000000 A 0 0 4[20] .eh_frame PROGBITS 0000000000002058 0000205800000000000000ac 0000000000000000 A 0 0 8[21] .init_array INIT_ARRAY 0000000000003db8 00002db80000000000000008 0000000000000008 WA 0 0 8[22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc00000000000000008 0000000000000008 WA 0 0 8[23] .dynamic DYNAMIC 0000000000003dc8 00002dc800000000000001f0 0000000000000010 WA 7 0 8[24] .got PROGBITS 0000000000003fb8 00002fb80000000000000048 0000000000000008 WA 0 0 8[25] .data PROGBITS 0000000000004000 000030000000000000000018 0000000000000000 WA 0 0 8[26] .bss NOBITS 0000000000004018 000030180000000000000008 0000000000000000 WA 0 0 1[27] .comment PROGBITS 0000000000000000 00003018000000000000002d 0000000000000001 MS 0 0 1[28] .symtab SYMTAB 0000000000000000 000030480000000000000378 0000000000000018 29 18 8[29] .strtab STRTAB 0000000000000000 000033c000000000000001e1 0000000000000000 0 0 1[30] .shstrtab STRTAB 0000000000000000 000035a1000000000000011a 0000000000000000 0 0 1
Key to Flags:W (write), A (alloc), X (execute), M (merge), S (strings), I (info),L (link order), O (extra OS processing required), G (group), T (TLS),C (compressed), x (unknown), o (OS specific), E (exclude),D (mbind), l (large), p (processor specific)从上面的信息中可以找到.rodata section的offset即该section在二进制文件中的偏移为2000。 下面使用hexdump命令查看二进制可执行文件文件test中的内容其中-C选项用于以十六进制单个字节的方式输出并将对应的ASCII码显示在右边。
$hexdump -C test
......
00002000 01 00 02 00 61 62 63 64 65 00 41 42 43 44 45 00 |....abcde.ABCDE.|
00002010 54 68 69 73 20 69 73 20 61 20 73 74 72 69 6e 67 |This is a string|
00002020 00 00 00 00 01 1b 03 3b 30 00 00 00 05 00 00 00 |.......;0.......|
...... 通过以上我们知道字符串字面量一般是保存在可执行文件的.rodata section中但是否所有字符串字面量都会保存在.rodata section中呢答案是否定的如下例所示。
例2
char array1[6] aaaaaa; //aaaaaa被添加到.data section作为全局数组的初始值
const char array2[6] bbbbbb //bbbbbb被添加到.rodata section因为它是只读的数据
int main()
{const char array3[6] cccccc //cccccc被添加到.rodata section无论是否有const修饰
} 对例2结果的验证在此跳过交给读者进行。下面进行结果的说明在上面的代码中array1是一个有字符串初始值的全局数组字符串字面量会直接添加到.data section中即保存全局变量的section且并不会在.rodata section保存。但array2是一个只读的有字符串初始值的全局数组字符串字面量还是会被添加到.rodata section。至于array3它和例1一样无论是否有const修饰字符串字面量都是被放在.rodata section。但要注意的是array3与array2和array1不同这个数组是保存在栈上的而数组的值cccccc是在程序执行前就在可执行代码中的.rodata段的。在进入main函数后栈上会开辟空间给array3然后将.rodata区的代码复制一份到array3栈上的空间在退出main函数后栈上空间被自动回收。