首页 > 代码库 > C++备忘录

C++备忘录

类的大小

  • 空类(不含成员变量和虚函数):因为对象不可能不占内存,否则这个对象怎么存在,所以C++规定空类对象内存大小为1。
    class EC
    {
    public:
    	EC(){}
    	~EC(){};
    	void EC1()
    	{
    		printf("EC1\n");
    	}
    };
    
    class EVC
    {
    public:
    	EVC(){}
    	~EVC(){};
    	void EVC1()
    	{
    		printf("EVC1\n");
    	}
    	virtual void VEVC1()
    	{
    		printf("EVC1\n");
    	}
    };
    
    int main(int argc, char*argv[])
    {
    	printf("%d\n", sizeof(EC));
    	printf("%d\n", sizeof(EVC));
    }

    输出结果:
    1
    4

  • 虚类(包含虚函数的类):因为声明虚函数后,类需要管理虚函数,所以创建了虚函数指针,所以类的对象大小还要计算这个虚表指针的大小。
  • 普通类:一般考虑像C的结构体那样即可(考虑数据对齐)。

函数调用方式

  • _cdecl : C\C++的默认调用方式,函数调用负责管理函数调用堆栈,支持不定参数。
  • _stdcall : WINAPI的调用方式,函数本身负责管理函数调用堆栈,不支持不定参数。
  • _fastcall : 寄存器方式传参,函数本身负责管理函数调用堆栈,不支持不定参数,VC默认在参数个数小于等于3的情况下使用这种方式。
    ;--- e:\code\win32\dre\helloworld\main.cpp --------------------------------------
    #include <stdio.h>
    
    int _cdecl Test(int a, int b)
    {
    009E13A0  push        ebp  
    009E13A1  mov         ebp,esp  
    009E13A3  sub         esp,0C0h  
    009E13A9  push        ebx  
    009E13AA  push        esi  
    009E13AB  push        edi  
    009E13AC  lea         edi,[ebp-0C0h]  
    009E13B2  mov         ecx,30h  
    009E13B7  mov         eax,0CCCCCCCCh  
    009E13BC  rep stos    dword ptr es:[edi]  
    	return a+b;
    009E13BE  mov         eax,dword ptr [a]  
    009E13C1  add         eax,dword ptr [b]  
    }
    009E13C4  pop         edi  
    009E13C5  pop         esi  
    009E13C6  pop         ebx  
    009E13C7  mov         esp,ebp  
    009E13C9  pop         ebp  
    009E13CA  ret								;无平衡堆栈,这类调用方式不用处理函数堆栈帧
    ;--- 无源文件 -----------------------------------------------------------------------
    
    
    ;--- e:\code\win32\dre\helloworld\main.cpp --------------------------------------
    
    int _stdcall Test1(int a, int b)
    {
    009E13F0  push        ebp  
    009E13F1  mov         ebp,esp  
    009E13F3  sub         esp,0C0h  
    009E13F9  push        ebx  
    009E13FA  push        esi  
    009E13FB  push        edi  
    009E13FC  lea         edi,[ebp-0C0h]  
    009E1402  mov         ecx,30h  
    009E1407  mov         eax,0CCCCCCCCh  
    009E140C  rep stos    dword ptr es:[edi]  
    	return a+b;
    009E140E  mov         eax,dword ptr [a]  
    009E1411  add         eax,dword ptr [b]  
    }
    009E1414  pop         edi  
    009E1415  pop         esi  
    009E1416  pop         ebx  
    009E1417  mov         esp,ebp  
    009E1419  pop         ebp  
    009E141A  ret         8						;平衡堆栈,这类调用方式需要处理函数堆栈帧
    ;--- 无源文件 -----------------------------------------------------------------------
    ;main
    ;{
    
    	Test(1,2);
    009E145E  push        2  
    009E1460  push        1  
    009E1462  call        Test (9E100Ah)  
    009E1467  add         esp,8					;平衡堆栈,调用者需要处理函数堆栈帧
    	Test1(1,2);
    009E146A  push        2  
    009E146C  push        1  
    009E146E  call        Test1 (9E107Dh)		;无平衡堆栈,被调用者已处理函数堆栈帧
    
    ;}

静态局部变量初始化

问:C\C++中如何实现静态变量多次调用但是只初始化一次 呢?
答:一定有方法的,编程语言能搞定他的!
问:到底是啥呢?
答:....
其实,如果不是看到相关的问题或者资料,这个问题想得人还真不多。其实这个问题实现的方法也简单,弄一个东西记录该静态变量是否初始化即可,编译器的一般做法是选取该变量附近的一个字节来记录该静态变量是否初始化了,但是因为记录该状态只需要一个Bit即可,而一字节有8Bit,所以这个字节可以被其他静态变量共享使用的。
	static int nSa = a;
000C143E  mov         eax,dword ptr [$S1 (0C713Ch)]  	; ===========BEG==============
000C1443  and         eax,1  
000C1446  jne         TestStaticVar+3Dh (0C145Dh)  
000C1448  mov         eax,dword ptr [$S1 (0C713Ch)]  
000C144D  or          eax,1  							; ===========END==============
000C1450  mov         dword ptr [$S1 (0C713Ch)],eax  
000C1455  mov         eax,dword ptr [a]  
000C1458  mov         dword ptr [nSa (0C7138h)],eax  
BEG到END部分的代码就是用来判断该静态变量是否已经初始化了的,此处用的是该字节的最低一个BIT