[英]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.