繁体   English   中英

C与C ++对象的静态初始化

[英]C vs C++ Static Initialization of Objects

我有一个关于初始化大量静态数据的问题。

请参阅下面的三个初始化静态数据集的示例。 我想了解以下所示方法对程序加载时间和内存占用的影响。 我现在真的不知道该如何评估。 我的构建环境仍在使用Visual Studio的桌面上,但是将使用GCC为VxWorks编译嵌入式目标。

传统上,我使用基本的C结构进行此类操作,尽管有充分的理由将这些数据移入C ++类。 动态内存分配在嵌入式应用程序中不受欢迎,并且在任何可能的情况下都避免使用。

据我所知,初始化C ++类的唯一方法是通过其构造函数,如下面的方法2所示。我想知道与方法1相比如何。在ROM(程序占用空间)方面是否存在任何明显的额外开销, RAM(内存占用量)还是程序加载时间? 在我看来,编译器可能可以优化一些琐碎的构造函数,但是我不确定这是否是常见行为。

我列出了方法3,尽管我认为这是一个坏主意,但我认为它是。 我还有其他想念的地方吗? 还有其他人以类似的方式初始化数据吗?

/* C-Style Struct Storage */
typedef struct{
    int a;
    int b;
}DATA_C;

/* CPP Style Class Storage */
class DATA_CPP{
public:
    int a;
    int b;
    DATA_CPP(int,int);
};
DATA_CPP::DATA_CPP(int aIn, int bIn){
    a = aIn;
    b = bIn;
}

/* METHOD 1: Direct C-Style Static Initialization */
DATA_C MyCData[5] = { {1,2},
                      {3,4},
                      {5,6},
                      {7,8},
                      {9,10}
                    };

/* METHOD 2: Direct CPP-Style Initialization */ 
DATA_CPP MyCppData[5] = { DATA_CPP(1,2),
                          DATA_CPP(3,4),
                          DATA_CPP(5,6),
                          DATA_CPP(7,8),
                          DATA_CPP(9,10),
                         };

/* METHOD 3: Cast C-Struct to CPP class */
DATA_CPP* pMyCppData2 = (DATA_CPP*) MyCData;

在C ++ 11中,您可以这样编写:

DATA_CPP obj = {1,2}; //Or simply : DATA_CPP obj {1,2}; i.e omit '='

代替

DATA_CPP obj(1,2);

扩展此内容,您可以编写:

DATA_CPP MyCppData[5] = { {1,2},
                          {3,4},
                          {5,6},
                          {7,8},
                          {9,10},
                         };

代替这个:

DATA_CPP MyCppData[5] = { DATA_CPP(1,2),
                          DATA_CPP(3,4),
                          DATA_CPP(5,6),
                          DATA_CPP(7,8),
                          DATA_CPP(9,10),
                         };

阅读有关统一初始化的信息。

我已经对此进行了一些研究,以为我会发布结果。 我在所有情况下都使用Visual Studio 2008。

这是在调试模式下Visual Studio中代码的反汇编视图:

/* METHOD 1: Direct C-Style Static Initialization */
DATA_C MyCData[5] = { {1,2},
                      {3,4},
                      {5,6},
                      {7,8},
                      {9,10},
                    };

/* METHOD 2: Direct CPP-Style Initialization */ 
DATA_CPP MyCppData[5] = { DATA_CPP(1,2),
010345C0  push        ebp  
010345C1  mov         ebp,esp 
010345C3  sub         esp,0C0h 
010345C9  push        ebx  
010345CA  push        esi  
010345CB  push        edi  
010345CC  lea         edi,[ebp-0C0h] 
010345D2  mov         ecx,30h 
010345D7  mov         eax,0CCCCCCCCh 
010345DC  rep stos    dword ptr es:[edi] 
010345DE  push        2    
010345E0  push        1    
010345E2  mov         ecx,offset MyCppData (1038184h) 
010345E7  call        DATA_CPP::DATA_CPP (103119Ah) 
                          DATA_CPP(3,4),
010345EC  push        4    
010345EE  push        3    
010345F0  mov         ecx,offset MyCppData+8 (103818Ch) 
010345F5  call        DATA_CPP::DATA_CPP (103119Ah) 
                          DATA_CPP(5,6),
010345FA  push        6    
010345FC  push        5    
010345FE  mov         ecx,offset MyCppData+10h (1038194h) 
01034603  call        DATA_CPP::DATA_CPP (103119Ah) 
                          DATA_CPP(7,8),
01034608  push        8    
0103460A  push        7    
0103460C  mov         ecx,offset MyCppData+18h (103819Ch) 
01034611  call        DATA_CPP::DATA_CPP (103119Ah) 
                          DATA_CPP(9,10),
01034616  push        0Ah  
01034618  push        9    
0103461A  mov         ecx,offset MyCppData+20h (10381A4h) 
0103461F  call        DATA_CPP::DATA_CPP (103119Ah) 
                         };
01034624  pop         edi  
01034625  pop         esi  
01034626  pop         ebx  
01034627  add         esp,0C0h 
0103462D  cmp         ebp,esp 
0103462F  call        @ILT+325(__RTC_CheckEsp) (103114Ah) 
01034634  mov         esp,ebp 
01034636  pop         ebp  

这里要注意的有趣一点是,至少在非优化调试模式下,程序内存使用和加载时间肯定会存在一些开销。 请注意,方法1的汇编指令为零,而方法2的汇编指令约为44。

我还以启用优化的方式在发布模式下运行了程序,这是经过删节的程序集输出:

?MyCData@@3PAUDATA_C@@A DD 01H              ; MyCData
    DD  02H
    DD  03H
    DD  04H
    DD  05H
    DD  06H
    DD  07H
    DD  08H
    DD  09H
    DD  0aH

?MyCppData@@3PAVDATA_CPP@@A DD 01H          ; MyCppData
    DD  02H
    DD  03H
    DD  04H
    DD  05H
    DD  06H
    DD  07H
    DD  08H
    DD  09H
    DD  0aH
END

似乎编译器确实优化了对C ++构造函数的调用。 我找不到在汇编代码中任何地方调用过构造函数的证据。

我以为我会再尝试一些。 我将构造函数更改为:

DATA_CPP::DATA_CPP(int aIn, int bIn){
    a = aIn + bIn;
    b = bIn;
}

再次,编译器对此进行了优化,从而得到了静态数据集:

?MyCppData@@3PAVDATA_CPP@@A DD 03H          ; MyCppData
    DD  02H
    DD  07H
    DD  04H
    DD  0bH
    DD  06H
    DD  0fH
    DD  08H
    DD  013H
    DD  0aH
END

有趣的是,编译器能够在编译期间对所有静态数据评估构造函数代码,并创建静态数据集,但仍不调用构造函数。

我以为我会尝试更多一些,对构造函数中的全局变量进行操作:

int globalvar;
DATA_CPP::DATA_CPP(int aIn, int bIn){
    a = aIn + globalvar;
    globalvar += a;
    b = bIn;
}

在这种情况下,编译器现在生成了汇编代码以在初始化期间调用构造函数:

    ??__EMyCppData@@YAXXZ PROC              ; `dynamic initializer for 'MyCppData'', COMDAT

; 35   : DATA_CPP MyCppData[5] = { DATA_CPP(1,2),

  00000 a1 00 00 00 00   mov     eax, DWORD PTR ?globalvar@@3HA ; globalvar
  00005 8d 48 01     lea     ecx, DWORD PTR [eax+1]
  00008 03 c1        add     eax, ecx
  0000a 89 0d 00 00 00
    00       mov     DWORD PTR ?MyCppData@@3PAVDATA_CPP@@A, ecx

; 36   :                           DATA_CPP(3,4),

  00010 8d 48 03     lea     ecx, DWORD PTR [eax+3]
  00013 03 c1        add     eax, ecx
  00015 89 0d 08 00 00
    00       mov     DWORD PTR ?MyCppData@@3PAVDATA_CPP@@A+8, ecx

; 37   :                           DATA_CPP(5,6),

  0001b 8d 48 05     lea     ecx, DWORD PTR [eax+5]
  0001e 03 c1        add     eax, ecx
  00020 89 0d 10 00 00
    00       mov     DWORD PTR ?MyCppData@@3PAVDATA_CPP@@A+16, ecx

; 38   :                           DATA_CPP(7,8),

  00026 8d 48 07     lea     ecx, DWORD PTR [eax+7]
  00029 03 c1        add     eax, ecx
  0002b 89 0d 18 00 00
    00       mov     DWORD PTR ?MyCppData@@3PAVDATA_CPP@@A+24, ecx

; 39   :                           DATA_CPP(9,10),

  00031 8d 48 09     lea     ecx, DWORD PTR [eax+9]
  00034 03 c1        add     eax, ecx
  00036 89 0d 20 00 00
    00       mov     DWORD PTR ?MyCppData@@3PAVDATA_CPP@@A+32, ecx
  0003c a3 00 00 00 00   mov     DWORD PTR ?globalvar@@3HA, eax ; globalvar

; 40   :                          };

  00041 c3       ret     0
??__EMyCppData@@YAXXZ ENDP              ; `dynamic initializer for 'MyCppData''

仅供参考,我发现此页面有助于设置Visual Studio以输出程序集: 如何从VS2005中的C文件获取汇编程序输出

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM