全局变量和局部变量在内存里的区别
一、预备知识—程序的内存分配一个由c/C++编译的程序占用的内存分为以下几个部分1、栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(.data),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(.bss)。 - 程序结束后由系统释放。4、文字常量区 —常量字符串就是放在这里的(.rodata)。 程序结束后由系统释放。5、程序代码区—存放函数体的二进制代码(.text)。?二、例子程序这是一个前辈写的,非常详细//main.cppint a = 0;????????? // 全局初始化区char *p1;?????????? // 全局未初始化区main(){? int b;??????????? // 栈区? char s[] = "abc"; // 栈区? char *p2;???????? // 栈区? char *p3 = "123456";???? // "123456\0" 在常量区,p3在栈区? static int c =0;??? ???? // 全局(静态)初始化区?? p1 = (char *)malloc(10);? p2 = (char *)malloc(20); // 分配得来的10和20字节的区域就在堆区?? strcpy(p1, "123456");??? // "123456\0" 放在常量区,编译器可能会将它????????????????????????????? // 与p3所指向的"123456"优化成一个地方。}???==============================================================?static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别??
答:
1)?全局变量(外部变量)的说明之前再冠以static?就构成了静态的全局变量。全局变量本身就是静态存储方式,?静态全局变量当然也是静态存储方式。?这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序,?当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。?而静态全局变量则限制了其作用域,?即只在定义该变量的源文件内有效,?在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。2)?从以上分析可以看出,?把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。 ?????????????????
3) static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件?
综上所述:
static全局变量与普通的全局变量有什么区别:
static全局变量只初使化一次,防止在其他文件单元中被引用;?
static局部变量和普通局部变量有什么区别:
static局部变量只被初始化一次,下一次依据上一次结果值;?
static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝??==============================================================一个C语言变量分配的实际例子:?? 我们来看看在可执行文件中,变量们会被分配在哪些区里.这里以可执行文件为例子,可执行文件有固定的内存加载地址,符号(函数/变量的名字)将来在内存里的地址连接器是可以提前确定的。?? 源程序编译连接的结果是形成1堆汇编指令代码,大致分为.text .data .bss等几个节区(section)。对于.exe文件和.so文件,全局和静态变量都放在.data 或.bss段(gas把源文件从头到尾扫描1遍,才知道一个变量的全部情况:是否定义;类型;是否初始化。然后把初始化的变量在.data段里分配位置和 空间,把没初始化的变量在.bss段里分配位置和空间,没定义的变量分配在.undef段)。汇编指令代码里全局变量表现为一个内存地址(全局变量在目标 文件里是一个偏移值,加载进内存里是一个内存地址)。临时变量在汇编代码里变成ebp/esp+n,表现为一个堆栈地址,化为程序正文(.text)的一 部分。有些变量的最终内存地址在加载进内存之前还不能确定,需要加载进内存才可以计算出来.? 全局变量 作用域是跨越多个源程序的。因此全局变量不能重名。静态变量作用域是位于单个源程序内。多个源程序可以有同名的全局静态变量。本例中,为了区分多个同名的静态变量,gcc 用 c444和c444.0 来加以区别。?[test@redhat]# more aaa.c
# include <stdio.h>int a111 = 0;????????????? # 全局变量 已初始化
char *p111 = "654321";???? # 全局指针变量 已经初始化
static int c444 = 9;?????? # 静态全局变量 已经初始化
static int c555;?????????? # 静态全局变量 未初始化
main()?
{?
??? int b222;????????????? # 局部变量
??? char s333[] = "abc";?? # 局部变量
??? char *p222;??????????? # 局部变量
??? char *p333 = "123456";??? # 局部变量
??? static int c444 =0;?????? # 已初始化静态局部变量,与前面静态全局变量重名
??? p111 = (char *)malloc(10);?
??? p222 = (char *)malloc(20);??? strcpy(p111, "123456");
}
[test@redhat]# gcc -o aaa ./aaa.c
?[test@redhat]# readelf -a ./aaa
ELF Header:
? Magic:?? 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00?
? Class:???????????????????????????? ELF32
? Data:????????????????????????????? 2's complement, little endian
? Version:?????????????????????????? 1 (current)
? OS/ABI:??????????????????????????? UNIX - System V
? ABI Version:?????????????????????? 0
? Type:????????????????????????????? EXEC (Executable file)
? Machine:?????????????????????????? Intel 80386
? Version:?????????????????????????? 0x1
? Entry point address:?????????????? 0x80482d0
? Start of program headers:????????? 52 (bytes into file)
? Start of section headers:????????? 2040 (bytes into file)
? Flags:???????????????????????????? 0x0
? Size of this header:?????????????? 52 (bytes)
? Size of program headers:?????????? 32 (bytes)
? Number of program headers:???????? 7
? Size of section headers:?????????? 40 (bytes)
? Number of section headers:???????? 27
? Section header string table index: 24Section Headers:???Addr是文件加载进内存时,每个section在内存中的虚拟地址
? [Nr] Name????????????? Type??????????? Addr???? Off??? Size?? ES Flg Lk Inf Al
? [ 0]?????????????????? NULL??????????? 00000000 000000 000000 00????? 0?? 0? 0
? [ 1] .interp?????????? PROGBITS??????? 08048114 000114 000013 00?? A? 0?? 0? 1
? [ 2] .note.ABI-tag???? NOTE??????????? 08048128 000128 000020 00?? A? 0?? 0? 4
? [ 3] .hash???????????? HASH??????????? 08048148 000148 00002c 04?? A? 4?? 0? 4
? [ 4] .dynsym?????????? DYNSYM????????? 08048174 000174 000060 10?? A? 5?? 1? 4
? [ 5] .dynstr?????????? STRTAB????????? 080481d4 0001d4 000053 00?? A? 0?? 0? 1
? [ 6] .gnu.version????? VERSYM????????? 08048228 000228 00000c 02?? A? 4?? 0? 2
? [ 7] .gnu.version_r??? VERNEED???????? 08048234 000234 000020 00?? A? 5?? 1? 4
? [ 8] .rel.dyn????????? REL???????????? 08048254 000254 000008 08?? A? 4?? 0? 4
? [ 9] .rel.plt????????? REL???????????? 0804825c 00025c 000018 08?? A? 4?? b? 4
? [10] .init???????????? PROGBITS??????? 08048274 000274 000017 00? AX? 0?? 0? 4
? [11] .plt????????????? PROGBITS??????? 0804828c 00028c 000040 04? AX? 0?? 0? 4
? [12] .text???????????? PROGBITS??????? 080482d0 0002d0 0001e4 00? AX? 0?? 0 16
? [13] .fini???????????? PROGBITS??????? 080484b4 0004b4 00001b 00? AX? 0?? 0? 4
? [14] .rodata?????????? PROGBITS??????? 080484d0 0004d0 00001a 00?? A? 0?? 0? 4
? [15] .eh_frame???????? PROGBITS??????? 080484ec 0004ec 000004 00?? A? 0?? 0? 4
? [16] .data???????????? PROGBITS??????? 080494f0 0004f0 00001c 00? WA? 0?? 0? 4
? [17] .dynamic????????? DYNAMIC???????? 0804950c 00050c 0000c8 08? WA? 5?? 0? 4
? [18] .ctors??????????? PROGBITS??????? 080495d4 0005d4 000008 00? WA? 0?? 0? 4
? [19] .dtors??????????? PROGBITS??????? 080495dc 0005dc 000008 00? WA? 0?? 0? 4
? [20] .jcr????????????? PROGBITS??????? 080495e4 0005e4 000004 00? WA? 0?? 0? 4
? [21] .got????????????? PROGBITS??????? 080495e8 0005e8 00001c 04? WA? 0?? 0? 4
? [22] .bss????????????? NOBITS????????? 08049604 000604 000008 00? WA? 0?? 0? 4
? [23] .comment????????? PROGBITS??????? 00000000 000604 000126 00????? 0?? 0? 1
? [24] .shstrtab???????? STRTAB????????? 00000000 00072a 0000ce 00????? 0?? 0? 1
? [25] .symtab?????????? SYMTAB????????? 00000000 000c30 0004c0 10???? 26? 2f? 4
? [26] .strtab?????????? STRTAB????????? 00000000 0010f0 000275 00????? 0?? 0? 1
Program Headers:
? Type?????????? Offset?? VirtAddr?? PhysAddr?? FileSiz MemSiz? Flg Align
? PHDR?????????? 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
? INTERP???????? 0x000114 0x08048114 0x08048114 0x00013 0x00013 R?? 0x1
????? [Requesting program interpreter: /lib/ld-linux.so.2]
? LOAD?????????? 0x000000 0x08048000 0x08048000 0x004f0 0x004f0 R E 0x1000
? LOAD?????????? 0x0004f0 0x080494f0 0x080494f0 0x00114 0x0011c RW? 0x1000
? DYNAMIC??????? 0x00050c 0x0804950c 0x0804950c 0x000c8 0x000c8 RW? 0x4
? NOTE?????????? 0x000128 0x08048128 0x08048128 0x00020 0x00020 R?? 0x4
? STACK????????? 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW? 0x4?Symbol table '.symtab' contains 76 entries:对于.exe文件,符号的Value 是将来加载进内存中的真实地址;对于.so文件Value需要重定位.
?? Num:??? Value? Size Type??? Bind?? Vis????? Ndx Name
???? 0: 00000000???? 0 NOTYPE? LOCAL? DEFAULT? UND?
???? 1: 08048114???? 0 SECTION LOCAL? DEFAULT??? 1?
???? 2: 08048128???? 0 SECTION LOCAL? DEFAULT??? 2?
???? 3: 08048148???? 0 SECTION LOCAL? DEFAULT??? 3?
???? 4: 08048174???? 0 SECTION LOCAL? DEFAULT??? 4?
???? 5: 080481d4???? 0 SECTION LOCAL? DEFAULT??? 5?
???? 6: 08048228???? 0 SECTION LOCAL? DEFAULT??? 6?
???? 7: 08048234???? 0 SECTION LOCAL? DEFAULT??? 7?
???? 8: 08048254???? 0 SECTION LOCAL? DEFAULT??? 8?
???? 9: 0804825c???? 0 SECTION LOCAL? DEFAULT??? 9?
??? 10: 08048274???? 0 SECTION LOCAL? DEFAULT?? 10?
??? 11: 0804828c???? 0 SECTION LOCAL? DEFAULT?? 11?
??? 12: 080482d0???? 0 SECTION LOCAL? DEFAULT?? 12?
??? 13: 080484b4???? 0 SECTION LOCAL? DEFAULT?? 13?
??? 14: 080484d0???? 0 SECTION LOCAL? DEFAULT?? 14?
??? 15: 080484ec???? 0 SECTION LOCAL? DEFAULT?? 15?
??? 16: 080494f0???? 0 SECTION LOCAL? DEFAULT?? 16?
??? 17: 0804950c???? 0 SECTION LOCAL? DEFAULT?? 17?
??? 18: 080495d4???? 0 SECTION LOCAL? DEFAULT?? 18?
??? 19: 080495dc???? 0 SECTION LOCAL? DEFAULT?? 19?
??? 20: 080495e4???? 0 SECTION LOCAL? DEFAULT?? 20?
??? 21: 080495e8???? 0 SECTION LOCAL? DEFAULT?? 21?
??? 22: 08049604???? 0 SECTION LOCAL? DEFAULT?? 22?
??? 23: 00000000???? 0 SECTION LOCAL? DEFAULT?? 23?
??? 24: 00000000???? 0 SECTION LOCAL? DEFAULT?? 24?
??? 25: 00000000???? 0 SECTION LOCAL? DEFAULT?? 25?
??? 26: 00000000???? 0 SECTION LOCAL? DEFAULT?? 26?
??? 27: 080482f4???? 0 FUNC??? LOCAL? DEFAULT?? 12 call_gmon_start
??? 28: 00000000???? 0 FILE??? LOCAL? DEFAULT? ABS crtstuff.c
??? 29: 080495d4???? 0 OBJECT? LOCAL? DEFAULT?? 18 __CTOR_LIST__
??? 30: 080495dc???? 0 OBJECT? LOCAL? DEFAULT?? 19 __DTOR_LIST__
??? 31: 080484ec???? 0 OBJECT? LOCAL? DEFAULT?? 15 __EH_FRAME_BEGIN__
??? 32: 080495e4???? 0 OBJECT? LOCAL? DEFAULT?? 20 __JCR_LIST__
??? 33: 080494f8???? 0 OBJECT? LOCAL? DEFAULT?? 16 p.0
??? 34: 08049604???? 1 OBJECT? LOCAL? DEFAULT?? 22 completed.1
??? 35: 08048320???? 0 FUNC??? LOCAL? DEFAULT?? 12 __do_global_dtors_aux
??? 36: 08048360???? 0 FUNC??? LOCAL? DEFAULT?? 12 frame_dummy
??? 37: 00000000???? 0 FILE??? LOCAL? DEFAULT? ABS crtstuff.c
??? 38: 080495d8???? 0 OBJECT? LOCAL? DEFAULT?? 18 __CTOR_END__
??? 39: 080495e0???? 0 OBJECT? LOCAL? DEFAULT?? 19 __DTOR_END__
??? 40: 080484ec???? 0 OBJECT? LOCAL? DEFAULT?? 15 __FRAME_END__
??? 41: 080495e4???? 0 OBJECT? LOCAL? DEFAULT?? 20 __JCR_END__
??? 42: 08048490???? 0 FUNC??? LOCAL? DEFAULT?? 12 __do_global_ctors_aux
??? 43: 00000000???? 0 FILE??? LOCAL? DEFAULT? ABS aaa.c
??? 44: 08049504???? 4 OBJECT? LOCAL? DEFAULT?? 16 c444???# static变量为LOCAL绑定属性(也即作用域) 已初始化静态变量存放在.data
??? 45: 08049508???? 4 OBJECT? LOCAL? DEFAULT?? 16 c444.0?# 已初始化静态变量存放在.data (多个源文件可以定义同名的静态变量)
??? 46: 08049608???? 4 OBJECT? LOCAL? DEFAULT?? 22 c555???# 未初始化静态变量存放在.bss
??? 47: 080494fc???? 4 OBJECT? GLOBAL DEFAULT?? 16 a111???# 全局变量为GLOBAL绑定属性? 已初始全局变量存放在.data
??? 48: 0804950c???? 0 OBJECT? GLOBAL DEFAULT?? 17 _DYNAMIC
??? 49: 080484d0???? 4 OBJECT? GLOBAL DEFAULT?? 14 _fp_hw
??? 50: 080494f0???? 0 NOTYPE? GLOBAL HIDDEN? ABS __fini_array_end
??? 51: 080494f4???? 0 OBJECT? GLOBAL HIDDEN?? 16 __dso_handle
??? 52: 08048440??? 66 FUNC??? GLOBAL DEFAULT?? 12 __libc_csu_fini
??? 53: 08048274???? 0 FUNC??? GLOBAL DEFAULT?? 10 _init
??? 54: 0804829c?? 427 FUNC??? GLOBAL DEFAULT? UND?malloc@@GLIBC_2.0???? 55: 080482d0???? 0 FUNC??? GLOBAL DEFAULT?? 12 _start
??? 56: 080494f0???? 0 NOTYPE? GLOBAL HIDDEN? ABS __fini_array_start
??? 57: 080483f0??? 71 FUNC??? GLOBAL DEFAULT?? 12 __libc_csu_init
??? 58: 08049500???? 4 OBJECT? GLOBAL DEFAULT?? 16 p111
??? 59: 08049604???? 0 NOTYPE? GLOBAL DEFAULT? ABS __bss_start
??? 60: 0804838c??? 89 FUNC??? GLOBAL DEFAULT?? 12 main
??? 61: 080482ac?? 251 FUNC??? GLOBAL DEFAULT? UND?__libc_start_main@@GLIBC?_
??? 62: 080494f0???? 0 NOTYPE? GLOBAL HIDDEN? ABS __init_array_end
??? 63: 080494f0???? 0 NOTYPE? WEAK?? DEFAULT?? 16 data_start
??? 64: 080484b4???? 0 FUNC??? GLOBAL DEFAULT?? 13 _fini
??? 65: 080494f0???? 0 NOTYPE? GLOBAL HIDDEN? ABS __preinit_array_end
??? 66: 08049604???? 0 NOTYPE? GLOBAL DEFAULT? ABS _edata
??? 67: 080495e8???? 0 OBJECT? GLOBAL DEFAULT?? 21 _GLOBAL_OFFSET_TABLE_
??? 68: 0804960c???? 0 NOTYPE? GLOBAL DEFAULT? ABS _end
??? 69: 080494f0???? 0 NOTYPE? GLOBAL HIDDEN? ABS __init_array_start
??? 70: 080484d4???? 4 OBJECT? GLOBAL DEFAULT?? 14 _IO_stdin_used
??? 71: 080494f0???? 0 NOTYPE? GLOBAL DEFAULT?? 16 __data_start
??? 72: 00000000???? 0 NOTYPE? WEAK?? DEFAULT? UND _Jv_RegisterClasses
??? 73: 080494f0???? 0 NOTYPE? GLOBAL HIDDEN? ABS __preinit_array_start
??? 74: 00000000???? 0 NOTYPE? WEAK?? DEFAULT? UND __gmon_start__
??? 75: 080482bc??? 48 FUNC??? GLOBAL DEFAULT? UND?strcpy@@GLIBC_2.0??文件./aaa加载进内存后,再看看变量的地址以及所在的区:
[test@redhat]# gdb ./aaa
GNU gdb 6.1.1
(gdb) disassemble main
Dump of assembler code for function main:
0x0804838c <main+0>:??? push?? %ebp
0x0804838d <main+1>:??? mov??? %esp,%ebp
0x0804838f <main+3>:??? sub??? $0x18,%esp
0x08048392 <main+6>:??? and??? $0xfffffff0,%esp
0x08048395 <main+9>:??? mov??? $0x0,%eax
0x0804839a <main+14>:?? sub??? %eax,%esp# char s333[] = "abc";
0x0804839c <main+16>:?? mov??? 0x80484df,%eax????????????# 0x80484df处为"abc",位于.rodata
0x080483a1 <main+21>:?? mov??? %eax,0xfffffff8(%ebp)?????# 0xfffffff8(%ebp) 为局部变量 char s333[]# char *p333 = "123456";
0x080483a4 <main+24>:?? movl?? $0x80484e3,0xfffffff0(%ebp)??# 0x80484e3处为"123456/0",位于.rodata; 0xfffffff0(%ebp) 为局部变量 char *p333# p111 = (char *)malloc(10);
0x080483ab <main+31>:?? sub??? $0xc,%esp
0x080483ae <main+34>:?? push?? $0xa??????????# 0xa=10 ; push $0xa后,此时堆栈esp值又减去4字节,相当于sub $0x10,%esp
0x080483b0 <main+36>:?? call?? 0x804829c <malloc>
0x080483b5 <main+41>:?? add??? $0x10,%esp
0x080483b8 <main+44>:?? mov??? %eax,0x8049500??# 0x8049500 为全局变量p111,位于.data# p222 = (char *)malloc(20);
0x080483bd <main+49>:?? sub??? $0xc,%esp
0x080483c0 <main+52>:?? push?? $0x14????????# 0x14=20 ; push $0xa后,此时堆栈esp值又减去4字节,相当于sub $0x10,%esp
0x080483c2 <main+54>:?? call?? 0x804829c <malloc>
0x080483c7 <main+59>:?? add??? $0x10,%esp
0x080483ca <main+62>:?? mov??? %eax,0xfffffff4(%ebp)??# 0xfffffff4(%ebp) 为局部变量p222# strcpy(p111, "123456");
0x080483cd <main+65>:?? sub??? $0x8,%esp
0x080483d0 <main+68>:?? push?? $0x80484e3????# 0x80484e3处内容为"123456/0",位于.rodata;?
0x080483d5 <main+73>:?? pushl? 0x8049500?????# 0x8049500 为全局变量p111,位于.data
0x080483db <main+79>:?? call?? 0x80482bc <strcpy>
0x080483e0 <main+84>:?? add??? $0x10,%esp
0x080483e3 <main+87>:?? leave??
0x080483e4 <main+88>:?? ret????
0x080483e5 <main+89>:?? nop????
0x080483e6 <main+90>:?? nop????
0x080483e7 <main+91>:?? nop????
0x080483e8 <main+92>:?? nop????
0x080483e9 <main+93>:?? nop????
0x080483ea <main+94>:?? nop????
0x080483eb <main+95>:?? nop????
0x080483ec <main+96>:?? nop????
0x080483ed <main+97>:?? nop????
0x080483ee <main+98>:?? nop????
0x080483ef <main+99>:?? nop????
End of assembler dump.
(gdb) q
[test@redhat]#