标签:cto 字节 字符 public 空间 除了 word 全局 允许
变量存储的四个区域 : 静态存储区,栈区,堆区,常量区。
静态存储区 : 静态变量,全局变量等
栈区 : 局部变量
堆区 : 通过malloc/operator new等函数申请的空间。
常量区 : 在函数中声明的数组并以指针形式接收。
字符串常量的几种放置方式 :
i) 在函数中声明的字符数组。
1 void test(){ 2 char ch1[100] = "aaaacccc"; 3 }
会被翻译成
1 test(): 2 push rbp 3 mov rbp, rsp 4 movabs rax, 7161677110935904609 5 mov edx, 0 6 mov QWORD PTR [rbp-112], rax 7 mov QWORD PTR [rbp-104], rdx 8 mov QWORD PTR [rbp-96], 0 9 mov QWORD PTR [rbp-88], 0 10 mov QWORD PTR [rbp-80], 0 11 mov QWORD PTR [rbp-72], 0 12 mov QWORD PTR [rbp-64], 0 13 mov QWORD PTR [rbp-56], 0 14 mov QWORD PTR [rbp-48], 0 15 mov QWORD PTR [rbp-40], 0 16 mov QWORD PTR [rbp-32], 0 17 mov QWORD PTR [rbp-24], 0 18 mov DWORD PTR [rbp-16], 0 19 nop 20 pop rbp 21 ret
由此可见,内存被存放在栈中,并且 字符串数组内容 直接以指令的形式在运行时四字节四字节地移动到栈区中。
由于这种实现方式,不宜以这种方式申请较大的 数组。
1) 可能会爆栈。
2) 运行时复制数组,速度挺慢。
ii) 在函数中声明字符指针并赋值。
字符串会被放入到只读区,作为字符串常量,指针变量则在栈中,且不可以用指针变量修改字符串常量(因为是只读的)。
1 void test(){ 2 char* ch1 = "aaaacccc"; 3 }
会被翻译成 :
1 .LC0: 2 .string "aaaacccc" 3 test(): 4 push rbp 5 mov rbp, rsp 6 mov QWORD PTR [rbp-8], OFFSET FLAT:.LC0 7 nop 8 pop rbp 9 ret
直接使用 label 声明字符串,在加载时,内存就已经复制好了。
可以看到,这里只有一份 .LC0,如若利用 ch1 对数组进行修改,运行时会报错 : Segmentation fault (core dumped)
这种方式适合只读的字符串,为了避免运行时报错,最好以
1 char * ch1 = "aaaacccc"; 2 char ch2[9] = "aaaacccc"; 3 void test(){ 4 ch1[0] = ‘c‘; 5 ch2[0] = ‘c‘; 6 }
会被翻译成 :
1 .LC0: 2 .string "aaaacccc" 3 ch1: 4 .quad .LC0 5 ch2: 6 .string "aaaacccc" 7 test(): 8 push rbp 9 mov rbp, rsp 10 mov rax, QWORD PTR ch1[rip] 11 mov BYTE PTR [rax], 99 12 mov BYTE PTR ch2[rip], 99 13 nop 14 pop rbp 15 ret
可以看到 ch1除了字符串本身,还有一个八字节指针的内存空间 (第三四行, .quad是个汇编伪指令 gas的指令,用来定义一个quard word也就是4字(8字节))。
而全局数组ch2则直接通过label+offset来进行访问和修改的。
iiii) 在对象中声明字符数组和字符指针
下面的代码运行时会出现段错误,原因和在函数中声明字符指针并通过其修改字符串常量一样,这样声明字符串会变为常量,存储在只读区内不允许修改。
1 struct str{ 2 private : 3 char* ch4 = "ch4"; 4 char ch5[4] = "ch5"; 5 public : 6 str(){ 7 ch4[1] = ‘0‘; 8 } 9 }; 10 void test(){ 11 str* s = new str(); 12 str* s2 = new str(); 13 }
会被翻译成 :
1 .LC0: 2 .string "ch4" 3 str::str() [base object constructor]: 4 push rbp 5 mov rbp, rsp 6 mov QWORD PTR [rbp-8], rdi 7 mov rax, QWORD PTR [rbp-8] 8 mov QWORD PTR [rax], OFFSET FLAT:.LC0 9 mov rax, QWORD PTR [rbp-8] 10 mov DWORD PTR [rax+8], 3500131 11 mov rax, QWORD PTR [rbp-8] 12 mov rax, QWORD PTR [rax] 13 add rax, 1 14 mov BYTE PTR [rax], 48 15 nop 16 pop rbp 17 ret 18 test(): 19 push rbp 20 mov rbp, rsp 21 push rbx 22 sub rsp, 24 23 mov edi, 16 24 call operator new(unsigned long) 25 mov rbx, rax 26 mov rdi, rbx 27 call str::str() [complete object constructor] 28 mov QWORD PTR [rbp-24], rbx 29 mov edi, 16 30 call operator new(unsigned long) 31 mov rbx, rax 32 mov rdi, rbx 33 call str::str() [complete object constructor] 34 mov QWORD PTR [rbp-32], rbx 35 nop 36 mov rbx, QWORD PTR [rbp-8] 37 leave 38 ret
有个有趣的现象,在类中直接赋初始值,但是翻译成汇编赋值操作被放入到了 构造函数 中。
标签:cto 字节 字符 public 空间 除了 word 全局 允许
原文地址:https://www.cnblogs.com/vizdl/p/13763067.html