C/C++编程基本功
C++其内容精深博大,任何一块都信手拈来者不多,究其精者更不多,不论何其原因,最重要一点就是其基本功之不扎实,对基础性东西不加以精深研究。我也是一样,经过几轮经典的面试,让我痛改以前的不扎实的作风,以此来磨砺自己。
一.内存管理篇
一个由C/C++编译的程序占用的内存分为以下几个部分:
1. 代码区 (Code section)
2. 数据区 (Data section)
3. 栈 (Stack)
4. 堆 (Heap)
解释说明:
1.数据区:
有人说数据区分全局区,静态区,文字常量区. 这些应该来说是细分数据区,其实这些被细分的区在OS里面还是被愿意称作为数据区。这里面存放的变量的值及占用的空间始终伴贯穿着整个程序的生命周期,直到程序结束后由系统收回。
下面给出一个程序例子,我们进行汇编之后可以看出变量所在的内存区域。
#include<string.h>
struct Employee
{
char firstname[32];
char lastname[32];
unsigned char age;
unsigned int salary;
};
struct Employee architect = {"Gil","Bates",45,100000};
struct Employee ceo = {"Reed","Almer",42,95000};
struct Employee drone;
void main()
{
strcpy(drone.firstname,"bill");
strcpy(drone.lastname,"blunden");
drone.age=35;
drone.salary=(int) (3.5);
return;
}
下面是VS.Net 2005汇编产生的代码:
.file "f:/Project/MyProject/Sample5/Sample5.cpp"
.global ?drone@@3UEmployee@@A ; drone
.global ?architect@@3UEmployee@@A ; architect
.global ?ceo@@3UEmployee@@A ; ceo
.bss
.local ?drone@@3UEmployee@@A,72 ; drone
.rdata
$SG8630:
.ascii "bill/000"
.space 3
$SG8631:
.ascii "blunden/000"
.data
?architect@@3UEmployee@@A: ; architect
.ascii "Gil/000"
.space 28
.ascii "Bates/000"
.space 26
.byte 0x2d
.space 3
.word 0x 186a 0
?ceo@@3UEmployee@@A: ; ceo
.ascii "Reed/000"
.space 27
.ascii "Almer/000"
.space 26
.byte 0x 2a
.space 3
.word 0x17318
; Function compile flags: /Odtp
; File f:/project/myproject/sample5/sample5.cpp
.text
.global ?main@@$$HYAHXZ ; main
?main@@$$HYAHXZ: ; main
; .proc.def D:I()
; Function Header:
; max stack depth = 2
; function size = 58 bytes
; local varsig tk = 0x0
; Exception Information:
; 0 handlers, each consisting of filtered handlers
; .proc.beg
; 20 : strcpy(drone.firstname,"bill");
ldsflda ?drone@@3UEmployee@@A
ldsflda $SG8630
call ?strcpy@@$$J0YAPADPADPBD@Z
pop
; 21 : strcpy(drone.lastname,"blunden");
ldsflda ?drone@@3UEmployee@@A
ldc.i4.s 32 ; i32 0x20
add
ldsflda $SG8631
call ?strcpy@@$$J0YAPADPADPBD@Z
pop
; 22 : drone.age=35;
ldsflda ?drone@@3UEmployee@@A
ldc.i4.s 64 ; i32 0x40
add
ldc.i4.s 35 ; u8 0x23
stind.i1
; 23 : drone.salary=(int) (3.5);
ldsflda ?drone@@3UEmployee@@A
ldc.i4.s 68 ; i32 0x44
add
ldc.i.3 3 ; u32 0x3
stind.i4
; 24 : return;
; 25 : }
ldc.i.0 0 ; i32 0x0
ret
.end ?main@@$$HYAHXZ ; main
; .proc.end.i4
_TEXT ENDS
PUBLIC __mep@?main@@$$HYAHXZ
PUBLIC _main
; COMDAT __mep@?main@@$$HYAHXZ
data SEGMENT
__mep@?main@@$$HYAHXZ TOKEN 0A 000009
; Function compile flags: /Odtp
data ENDS
; COMDAT _main
_TEXT SEGMENT
_main PROC ; COMDAT
jmp DWORD PTR __mep@?main@@$$HYAHXZ
_main ENDP
_TEXT ENDS
END
以上我们就可以清楚的知道数据区存储的是全局变量和本地变量,想想看其实汇编其实也不是蛮难的吗J。
2.代码区
存放函数体的二进制代码.
下面是我引用《Memory Management: Algorithms and Implementation》一书上面的例子,我发现很有趣。
/* --codedata.c-- */
#include<stdio.h>
void code()
{
/*
on Intel, each instruction is 4 bytes:
encoded as 0x66 0xb8 0x07 0x00
*/
_asm MOV AX,0x07
_asm MOV AX,0x07
_asm MOV AX,0x07
_asm MOV AX,0x07
/* 16 bytes total */
return;
}
void main()
{
char *cptr;步
short reg;
code();
_asm MOV reg,AX
printf("reg=%d/n",reg);
cptr = (char*)code;
cptr[0]='d'; cptr[1]='a';cptr[2]='t';cptr[3]='a';
cptr[4]=(char)0;
printf("cptr[]=%s/n",cptr);
return;
}
代码有意思的一部分就是把代码区变为数据区(红色标注部分),OS有规定代码区只有被访问权限,没有写的权限。下面是在windows下面执行时发出的警告信息。
(图形1-1)
3.栈
栈是是向低地址扩张的先进后出的数据结构,是一块续的内存区域。每一个栈都有一个栈指针(如图1-2),用来存储栈中最后一项元素的低地址。当新元素被加进栈中,栈指针就会相应的减少,这时的栈指针指向指新元素的第一个字节的地址。
(图形1-2)
/* sample2.cpp */
int main()
{
int i=0; // i在栈上
int sum = 0; // sum在栈上
for(i=0; i<100; i++)
sum+=i;
printf(“%d”,sum);
}
4. 堆
是向高地址扩展的数据结构,是不连续的内存区域.
(未完,待续)