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

时间:2014-04-16 04:14:09

标签: c++ c arrays initialization

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

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

传统上,我已经使用了基本的C-structs来处理这类事情,尽管有充分的理由将这些数据转移到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;

2 个答案:

答案 0 :(得分:1)

在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),
                         };

了解统一初始化。

答案 1 :(得分:1)

我已经对此做了一些研究,以为我发布了结果。我在这里使用了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输出程序集: How do I get the assembler output from a C file in VS2005