【编译和链接七】目标文件里的变量和常量都存储在哪儿?(全局变量、局部变量、static、const、define)
- 一、变量
- 1、全局变量
- 1.1、全局变量存储在数据区.data
- 2、局部变量
- 2.1、局部变量存储在代码区.text——也就是栈上
- 3、static变量
- 3.1、全局static_存储在数据区.data
- 3.2、局部static_也存储在数据区.data
- 二、常量
- 1、const
- 1.1、==赋值的全局const存储在只读数据区.rodata==
- 1.2、==未赋值的全局const存储在COM——就是链接后的.bss段==
- 1.3、局部const_存储在代码区.text——也就是栈上
- 2、define——宏常量
- 2.1、宏常量存储在只读数据区——rodata
- 3. 字符串常量
- 1、==字符串常量存储在只读数据区.rodata==
- 三、扩展:
- 1、常量、变量
- 1.1、声明变量
- 1.2、使用常量
- 2、static介绍
- 2.1、static 局部变量
- 2.2、static 全局变量
- 2.3、C++ static静态成员变量
- 2.4、C++ static静态成员函数详解
一、变量
1、全局变量
- 代码
// hello.c
#include<stdio.h>char g_char[] = "hello world"; //存储在.data
char g_u; //存储在.bbsint main()
{return 0;
}
- 生成目标文件并查看目标文件
$ gcc -c hello.c -o hello.o
$ objdump -x -s -d hello.o
1.1、全局变量存储在数据区.data
[dev1@localhost test01]$ gcc -c hello.c -o hello.o
[dev1@localhost test01]$ objdump -x -s -d hello.ohello.o: 文件格式 elf64-x86-64
hello.o
体系结构:i386:x86-64,标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000节:
Idx Name Size VMA LMA File off Algn0 .text 0000000b 0000000000000000 0000000000000000 00000040 2**0CONTENTS, ALLOC, LOAD, READONLY, CODE1 .data 0000000c 0000000000000000 0000000000000000 0000004b 2**0CONTENTS, ALLOC, LOAD, DATA2 .bss 00000000 0000000000000000 0000000000000000 00000057 2**0ALLOC3 .comment 0000002e 0000000000000000 0000000000000000 00000057 2**0CONTENTS, READONLY4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 00000085 2**0CONTENTS, READONLY5 .eh_frame 00000038 0000000000000000 0000000000000000 00000088 2**3CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 hello.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g O .data 000000000000000c g_char
0000000000000001 O *COM* 0000000000000001 g_u
0000000000000000 g F .text 000000000000000b mainContents of section .text:0000 554889e5 b8000000 005dc3 UH.......].
Contents of section .data:0000 68656c6c 6f20776f 726c6400 hello world.
Contents of section .comment:0000 00474343 3a202847 4e552920 342e382e .GCC: (GNU) 4.8.0010 35203230 31353036 32332028 52656420 5 20150623 (Red 0020 48617420 342e382e 352d3434 2900 Hat 4.8.5-44).
Contents of section .eh_frame:0000 14000000 00000000 017a5200 01781001 .........zR..x..0010 1b0c0708 90010000 1c000000 1c000000 ................0020 00000000 0b000000 00410e10 8602430d .........A....C.0030 06460c07 08000000 .F...... Disassembly of section .text:0000000000000000 <main>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: b8 00 00 00 00 mov $0x0,%eax9: 5d pop %rbpa: c3 retq
[dev1@localhost test01]$
2、局部变量
- 代码
// main.c
#include<stdio.h>
int main()
{char local_char[] = "hello world\n"; //存储在.datachar loacla_u; //存储在bbsprintf(local_char);return 0;
}
2.1、局部变量存储在代码区.text——也就是栈上
- hello world 存储在.data
[root@localhost test04_define]# gcc main.c
[root@localhost test04_define]# ./a.out
hello world
[root@localhost test04_define]# gcc -c main.c -o hello.o
[root@localhost test04_define]# objdump -x -s -d hello.ohello.o: 文件格式 elf64-x86-64
hello.o
体系结构:i386:x86-64,标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000节:
Idx Name Size VMA LMA File off Algn0 .text 00000039 0000000000000000 0000000000000000 00000040 2**0CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE1 .data 00000000 0000000000000000 0000000000000000 00000079 2**0CONTENTS, ALLOC, LOAD, DATA2 .bss 00000000 0000000000000000 0000000000000000 00000079 2**0ALLOC3 .comment 0000002e 0000000000000000 0000000000000000 00000079 2**0CONTENTS, READONLY4 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000a7 2**0CONTENTS, READONLY5 .eh_frame 00000038 0000000000000000 0000000000000000 000000a8 2**3CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 main.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g F .text 0000000000000039 main
0000000000000000 *UND* 0000000000000000 printfContents of section .text:0000 554889e5 4883ec10 48b86865 6c6c6f20 UH..H...H.hello 0010 776f4889 45f0c745 f8726c64 0ac645fc woH.E..E.rld..E.0020 00488d45 f04889c7 b8000000 00e80000 .H.E.H..........0030 0000b800 000000c9 c3 .........
Contents of section .comment:0000 00474343 3a202847 4e552920 342e382e .GCC: (GNU) 4.8.0010 35203230 31353036 32332028 52656420 5 20150623 (Red 0020 48617420 342e382e 352d3434 2900 Hat 4.8.5-44).
Contents of section .eh_frame:0000 14000000 00000000 017a5200 01781001 .........zR..x..0010 1b0c0708 90010000 1c000000 1c000000 ................0020 00000000 39000000 00410e10 8602430d ....9....A....C.0030 06740c07 08000000 .t...... Disassembly of section .text:0000000000000000 <main>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: 48 83 ec 10 sub $0x10,%rsp8: 48 b8 68 65 6c 6c 6f movabs $0x6f77206f6c6c6568,%raxf: 20 77 6f 12: 48 89 45 f0 mov %rax,-0x10(%rbp)16: c7 45 f8 72 6c 64 0a movl $0xa646c72,-0x8(%rbp)1d: c6 45 fc 00 movb $0x0,-0x4(%rbp)21: 48 8d 45 f0 lea -0x10(%rbp),%rax25: 48 89 c7 mov %rax,%rdi28: b8 00 00 00 00 mov $0x0,%eax2d: e8 00 00 00 00 callq 32 <main+0x32>2e: R_X86_64_PC32 printf-0x432: b8 00 00 00 00 mov $0x0,%eax37: c9 leaveq 38: c3 retq
[root@localhost test04_define]#
3、static变量
- 代码
// main.c
#include<stdio.h>
const char const_g[]="hello global";
int main()
{const char const_l[]="hello local";return 0;
}
- 生成目标文件并查看目标文件
$ gcc -c hello.c -o hello.o
$ objdump -x -s -d hello.o
3.1、全局static_存储在数据区.data
- hello global存储在.data
3.2、局部static_也存储在数据区.data
- hello local 存储在.data
[root@localhost test04_define]# gcc main.c
[root@localhost test04_define]# ./a.out
hello global
hello local
[root@localhost test04_define]# objdump -x -s -d a.outSYMBOL TABLE:0000000000601034 l O .data 000000000000000e static_global0000000000601042 l O .data 000000000000000d static_local.2179000000000040052d <main>:40052d: 55 push %rbp40052e: 48 89 e5 mov %rsp,%rbp400531: bf 34 10 60 00 mov $0x601034,%edi400536: b8 00 00 00 00 mov $0x0,%eax40053b: e8 d0 fe ff ff callq 400410 <printf@plt>400540: bf 42 10 60 00 mov $0x601042,%edi400545: b8 00 00 00 00 mov $0x0,%eax40054a: e8 c1 fe ff ff callq 400410 <printf@plt>40054f: b8 00 00 00 00 mov $0x0,%eax400554: 5d pop %rbp400555: c3 retq 400556: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)40055d: 00 00 00
二、常量
1、const
const修饰的变量是常量
- 代码
// hello.c
#include<stdio.h>
const char g_char[]="hello global\n";
const char g_char_undefined; int main()
{const char l_char[] = "hello local\n";const char l_char_undefined;printf(g_char);printf(l_char);return 0;
}
- 生成目标文件并查看目标文件
[root@localhost test04_const]# gcc -c main.c -o hello.o
[root@localhost test04_const]# objdump -x -s -d hello.ohello.o: 文件格式 elf64-x86-64
hello.o
体系结构:i386:x86-64,标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000节:
Idx Name Size VMA LMA File off Algn0 .text 00000043 0000000000000000 0000000000000000 00000040 2**0CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE1 .data 00000000 0000000000000000 0000000000000000 00000083 2**0CONTENTS, ALLOC, LOAD, DATA2 .bss 00000000 0000000000000000 0000000000000000 00000083 2**0ALLOC3 .rodata 0000001b 0000000000000000 0000000000000000 00000083 2**0CONTENTS, ALLOC, LOAD, READONLY, DATA4 .comment 0000002e 0000000000000000 0000000000000000 0000009e 2**0CONTENTS, READONLY5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000cc 2**0CONTENTS, READONLY6 .eh_frame 00000038 0000000000000000 0000000000000000 000000d0 2**3CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 main.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .rodata 0000000000000000 .rodata
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g O .rodata 000000000000000e g_char
0000000000000001 O *COM* 0000000000000001 g_char_undefined
0000000000000000 g F .text 0000000000000043 main
0000000000000000 *UND* 0000000000000000 puts
0000000000000000 *UND* 0000000000000000 printfContents of section .text:0000 554889e5 4883ec10 48b86865 6c6c6f20 UH..H...H.hello 0010 6c6f4889 45f0c745 f863616c 0ac645fc loH.E..E.cal..E.0020 00bf0000 0000e800 00000048 8d45f048 ...........H.E.H0030 89c7b800 000000e8 00000000 b8000000 ................0040 00c9c3 ...
Contents of section .rodata:0000 68656c6c 6f20676c 6f62616c 0a006865 hello global..he0010 6c6c6f20 676c6f62 616c00 llo global.
Contents of section .comment:0000 00474343 3a202847 4e552920 342e382e .GCC: (GNU) 4.8.0010 35203230 31353036 32332028 52656420 5 20150623 (Red 0020 48617420 342e382e 352d3434 2900 Hat 4.8.5-44).
Contents of section .eh_frame:0000 14000000 00000000 017a5200 01781001 .........zR..x..0010 1b0c0708 90010000 1c000000 1c000000 ................0020 00000000 43000000 00410e10 8602430d ....C....A....C.0030 067e0c07 08000000 .~...... Disassembly of section .text:0000000000000000 <main>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: 48 83 ec 10 sub $0x10,%rsp8: 48 b8 68 65 6c 6c 6f movabs $0x6f6c206f6c6c6568,%raxf: 20 6c 6f 12: 48 89 45 f0 mov %rax,-0x10(%rbp)16: c7 45 f8 63 61 6c 0a movl $0xa6c6163,-0x8(%rbp)1d: c6 45 fc 00 movb $0x0,-0x4(%rbp)21: bf 00 00 00 00 mov $0x0,%edi22: R_X86_64_32 .rodata+0xe26: e8 00 00 00 00 callq 2b <main+0x2b>27: R_X86_64_PC32 puts-0x42b: 48 8d 45 f0 lea -0x10(%rbp),%rax2f: 48 89 c7 mov %rax,%rdi32: b8 00 00 00 00 mov $0x0,%eax37: e8 00 00 00 00 callq 3c <main+0x3c>38: R_X86_64_PC32 printf-0x43c: b8 00 00 00 00 mov $0x0,%eax41: c9 leaveq 42: c3 retq
[root@localhost test04_const]#
1.1、赋值的全局const存储在只读数据区.rodata
- hello global存储在.rodata
0000000000000000 g O .rodata 000000000000000e g_char
0000000000000001 O *COM* 0000000000000001 g_char_undefined
1.2、未赋值的全局const存储在COM——就是链接后的.bss段
- g_char_undefined存储在.rodata
0000000000000001 O *COM* 0000000000000001 g_char_undefined
1.3、局部const_存储在代码区.text——也就是栈上
- hello local 存储在.rodata
68 就是字符h
65就是e…
0000000000000000 <main>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: 48 83 ec 10 sub $0x10,%rsp8: 48 b8 68 65 6c 6c 6f movabs $0x6f6c206f6c6c6568,%rax
2、define——宏常量
-
demo
-
查看
[root@localhost test04_define]# gcc main.c
[root@localhost test04_define]# ./a.out
hello global
[root@localhost test04_define]# gcc -c main.c -o hello.o
[root@localhost test04_define]# objdump -x -s -d hello.ohello.o: 文件格式 elf64-x86-64
hello.o
体系结构:i386:x86-64,标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000节:
Idx Name Size VMA LMA File off Algn0 .text 00000015 0000000000000000 0000000000000000 00000040 2**0CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE1 .data 00000000 0000000000000000 0000000000000000 00000055 2**0CONTENTS, ALLOC, LOAD, DATA2 .bss 00000000 0000000000000000 0000000000000000 00000055 2**0ALLOC3 .rodata 0000000d 0000000000000000 0000000000000000 00000055 2**0CONTENTS, ALLOC, LOAD, READONLY, DATA4 .comment 0000002e 0000000000000000 0000000000000000 00000062 2**0CONTENTS, READONLY5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 00000090 2**0CONTENTS, READONLY6 .eh_frame 00000038 0000000000000000 0000000000000000 00000090 2**3CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 main.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .rodata 0000000000000000 .rodata
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g F .text 0000000000000015 main
0000000000000000 *UND* 0000000000000000 putsContents of section .text:0000 554889e5 bf000000 00e80000 0000b800 UH..............0010 0000005d c3 ...].
Contents of section .rodata:0000 68656c6c 6f20676c 6f62616c 00 hello global.
Contents of section .comment:0000 00474343 3a202847 4e552920 342e382e .GCC: (GNU) 4.8.0010 35203230 31353036 32332028 52656420 5 20150623 (Red 0020 48617420 342e382e 352d3434 2900 Hat 4.8.5-44).
Contents of section .eh_frame:0000 14000000 00000000 017a5200 01781001 .........zR..x..0010 1b0c0708 90010000 1c000000 1c000000 ................0020 00000000 15000000 00410e10 8602430d .........A....C.0030 06500c07 08000000 .P...... Disassembly of section .text:0000000000000000 <main>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: bf 00 00 00 00 mov $0x0,%edi5: R_X86_64_32 .rodata9: e8 00 00 00 00 callq e <main+0xe>a: R_X86_64_PC32 puts-0x4e: b8 00 00 00 00 mov $0x0,%eax13: 5d pop %rbp14: c3 retq
[root@localhost test04_define]#
2.1、宏常量存储在只读数据区——rodata
0000000000000000 <main>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: bf 00 00 00 00 mov $0x0,%edi5: R_X86_64_32 .rodata
3. 字符串常量
- 代码
// main.c
#include<stdio.h>int main()
{printf("hello world\n");return 0;
}
- 生成目标文件并查看目标文件
$ gcc -c main.c -o hello.o
$ objdump -x -s -d hello.o
1、字符串常量存储在只读数据区.rodata
- hello world 存储在.rodata
0000000000000000 <main>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: bf 00 00 00 00 mov $0x0,%edi5: R_X86_64_32 .rodata9: e8 00 00 00 00 callq e <main+0xe>
三、扩展:
1、常量、变量
变量是内存变量的简称,用于存放数据。
1.1、声明变量
-
变量在使用之前要先声明。
-
语法:数据类型 变量名
C++常用的数据类型有五种:整数(int)、浮点数(float和double)、字符(char)、字符串(string)和布尔(bool)。
变量在声明的时候可以赋初始值。
语法:数据类型 变量名=值
- 1.2、变量的赋值
语法:变量名=值
1.2、使用常量
常量是程序中固定不变的数据。
-
2.1、宏常量
一般在main函数的上面声明,用大写命名。
语法:#define 常量名 值 -
2.2、const修饰的变量
在程序的任何地方都可以声明。
语法:const 数据类型 常量名=值 -
2.3、常量的特点
程序中不允许改变常量的值,否则编译的时候会报错。
2、static介绍
我们通常将不需要被其他模块调用的全局变量或函数用 static 关键字来修饰,static 能够将全局变量和函数的作用域限制在当前文件中。
2.1、static 局部变量
static 除了可以修饰全局变量,还可以修饰局部变量,被 static 修饰的变量统称为静态变量(Static Variable)。
不管是全局变量还是局部变量,只要被 static 修饰,都会存储在全局数据区(全局变量本来就存储在全局数据区,即使不加 static)。
全局数据区的数据在程序启动时就被初始化,一直到程序运行结束才会被操作系统回收内存;对于函数中的静态局部变量,即使函数调用结束,内存也不会销毁。
注意:全局数据区的变量只能被初始化(定义)一次,以后只能改变它的值,不能再被初始化,即使有这样的
语句,也无效。
#include <stdio.h>int func() {// 也可以不赋初值 0,静态数据区的变量默认初始化为 0static int n = 0;n++;printf("Function is called %d times.\n", n);return n;
}int main()
{int i, n = 0;for (i = 0; i <= 3; i++) {func();}printf("n = %d\n", n);return 0;
}
输出
Function is called 1 times.
Function is called 2 times.
Function is called 3 times.
Function is called 4 times.
n = 0
2.2、static 全局变量
-
全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。
-
普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。
-
静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。
在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。
函数
函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。其特性如下:
- 静态函数只能在声明它的文件中可见,其他文件不能引用该函数
不同的文件可以使用相同名字的静态函数,互不影响
1、c语言中文网——C语言static变量和函数
2、C语言 static变量和函数详解
2.3、C++ static静态成员变量
对象的内存中包含了成员变量,不同的对象占用不同的内存(已在《C++对象的内存模型》中提到),这使得不同对象的成员变量相互独立,它们的值不受其他对象的影响。例如有两个相同类型的对象 a、b,它们都有一个成员变量 m_name,那么修改 a.m_name 的值不会影响 b.m_name 的值。
可是有时候我们希望在多个对象之间共享数据,
- 在C++中,我们可以使用静态成员变量来实现多个对象共享数据的目标。静态成员变量是一种特殊的成员变量,它被关键字static修饰
2.4、C++ static静态成员函数详解
在类中,static 除了可以声明静态成员变量,还可以声明静态成员函数。
普通成员函数可以访问所有成员(包括成员变量和成员函数),
- 静态成员函数只能访问静态成员。
C++ static静态成员函数详解