我有一个关于相当大的静态数据集的初始化的问题。
请参阅下面的三个初始化静态数据集的示例。我想了解程序加载时间&下面显示的方法的内存占用含义。我现在真的不知道如何自己评估。我的构建环境仍然使用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;
答案 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