先看几个实例
代码1
#include <iostream>
int data_arr[32768];
int main()
{
data_arr[1] += 11;
std::cout<<"data_arr[1]: " << data_arr[1] << std::endl;
return data_arr[1];
}
上述代码在Win10 X64,MSVC Release模式下编译,编译得到的二进制文件大小为15KB左右。
代码2
#include <iostream>
int data_arr[32768] = {0,0,0,0,0};
int main()
{
data_arr[1] += 11;
std::cout<<"data_arr[1]: " << data_arr[1] << std::endl;
return data_arr[1];
}
上述代码在Win10 X64,MSVC Release模式下编译,编译得到的二进制文件大小为15KB左右。
代码3
#include <iostream>
int data_arr[32768] = {2};
int main()
{
data_arr[1] += 11;
std::cout<<"data_arr[1]: " << data_arr[1] << std::endl;
return data_arr[1];
}
上述代码在Win10 X64,MSVC Release模式下编译,编译得到的二进制文件大小为143KB左右。
代码4
#include <iostream>
int data_arr[32768] = {1,2,3,4,5,6};
int main()
{
data_arr[1] += 11;
std::cout<<"data_arr[1]: " << data_arr[1] << std::endl;
return data_arr[1];
}
上述代码在Win10 X64,MSVC Release模式下编译,编译得到的二进制文件大小为143KB左右。
情况分析
为何前两份代码和后两份代码编译之后的二进制文件大小会差异这么大?
原因就是全局变量data_arr 定义的方式不同。前两份代码中data_arr变量定义但是没有初始化或初始化为0,此变量运行时实际会存放在bss段(Block Started by Symbol Segment)中,只存符号(只有占位符),没有初始化的具体的值,自然也就不需要在二进制文件中保存这些值,因此文件很小。
而后两份代码中data_arr变量定义并初始化为具体的值,此变量运行时实际会存放到data段中,又因为初始化了具体的值,这些值需要保存在二进制程序源文件中,所以文件就变大了。
确认data_arr变量在内存中的布局
在Visual Studio 2022中用对应的.map文件,来确认data_arr变量在内存中的具体布局情况,看看它们运行时到底存放在哪个内存段中。
生成.map和了解.map文件内容请见: Visual Studio(2022)生成链接过程的.map映射文件以及.map映射文件的内容说明_含影的博客-CSDN博客
前两份代码对应的的.map文件摘录如下:
Preferred load address is 0000000140000000
Start Length Name Class
0001:000013d0 00000091H .text$x CODE
0002:00000ec8 00000788H .idata$6 DATA
0003:00000000 00000040H .data DATA
0003:00000040 00020088H .bss DATA
0004:00000000 00000240H .pdata DATA
Address Publics by Value Rva+Base Lib:Object
0003:00000030 __scrt_ucrt_dll_is_in_use 0000000140005030 MSVCRT:ucrt_stubs.obj
0003:00000040 ?data_arr@@3PAHA 0000000140005040 ccwindowsMain.obj
从上面的.map文件内容,可以看到,data_arr变量,被分配到地址为0003:00000040这个内存空间中,而这个内存空间就是bss段(见于:0003:00000040 00020088H .bss)。
后两份代码对应的的.map文件摘录如下:
demo_ccwindows
Preferred load address is 0000000140000000
Start Length Name Class
0001:00000000 00001390H .text$mn CODE
0002:00000ec8 00000788H .idata$6 DATA
0003:00000000 00020040H .data DATA
0003:00020040 00000088H .bss DATA
0004:00000000 00000240H .pdata DATA
Address Publics by Value Rva+Base Lib:Object
0002:00000c90 __NULL_IMPORT_DESCRIPTOR 0000000140003c90 msvcprt:MSVCP140.dll
0003:00000000 ?data_arr@@3PAHA 0000000140005000 ccwindowsMain.obj
从上面的.map文件内容,可以看到,data_arr变量,被分配到地址为0003:00000000这个内存空间中,而这个内存空间就是data段(见于:0003:00000000 00020040H .data)。
复杂一点的代码示例
#include <iostream>
#include <string>
int data_arr[32768] = {1, 2, 3, 4, 5, 6, 7, 8};
volatile const static int Major_version = 22;
volatile const float Minor_Version = 17;
std::string base_str_0 = "sssssAAAAA00000";
int parseSignal(int signal)
{
static int baseSignal = 1013;
std::string base_str = "sssssAAAAA11111";
if (signal > 15)
{
base_str += "sssssAAAAA22222" + base_str_0;
signal *= base_str.size();
}
return signal * baseSignal;
}
int main(int argc, char** argv)
{
data_arr[1] += 11;
std::cout << "data_arr[1]: " << data_arr[1] << std::endl;
return data_arr[1] + (Major_version << argc) + Minor_Version * argc + parseSignal(argc >> 1);
}
对应的.map内容节选如下:
Preferred load address is 0000000140000000
Start Length Name Class
0001:00000000 00000050H .text$di CODE
0001:00000050 000021a0H .text$mn CODE
0001:000021f0 00000040H .text$mn$00 CODE
0001:00002230 000000c0H .text$x CODE
0001:000022f0 00000064H .text$yd CODE
0002:00000000 00000278H .idata$5 DATA
0002:00000278 00000038H .00cfg DATA
0002:000002b0 00000008H .CRT$XCA DATA
0002:000002b8 00000008H .CRT$XCAA DATA
0002:000002c0 00000008H .CRT$XCU DATA
0002:000002c8 00000008H .CRT$XCZ DATA
0002:000002d0 00000008H .CRT$XIA DATA
0002:000002d8 00000008H .CRT$XIAA DATA
0002:000002e0 00000008H .CRT$XIAC DATA
0002:000002e8 00000008H .CRT$XIZ DATA
0002:000002f0 00000008H .CRT$XPA DATA
0002:000002f8 00000008H .CRT$XPZ DATA
0002:00000300 00000008H .CRT$XTA DATA
0002:00000308 00000008H .CRT$XTZ DATA
0002:00000310 00000000H .gehcont$y DATA
0002:00000310 00000000H .gfids$y DATA
0002:00000310 000002f0H .rdata DATA
0002:00000600 00000080H .rdata$CastGuardVftablesA DATA
0002:00000680 00000080H .rdata$CastGuardVftablesC DATA
0002:00000700 000001f4H .rdata$r DATA
0002:000008f4 000000a8H .rdata$voltmd DATA
0002:0000099c 000003c4H .rdata$zzzdbg DATA
0002:00000d60 00000008H .rtc$IAA DATA
0002:00000d68 00000008H .rtc$IZZ DATA
0002:00000d70 00000008H .rtc$TAA DATA
0002:00000d78 00000008H .rtc$TZZ DATA
0002:00000d80 00000418H .xdata DATA
0002:00001198 000000ecH .xdata$x DATA
0002:00001284 00000000H .edata DATA
0002:00001284 000000b4H .idata$2 DATA
0002:00001338 00000018H .idata$3 DATA
0002:00001350 00000278H .idata$4 DATA
0002:000015c8 00000868H .idata$6 DATA
0003:00000000 00020078H .data DATA
0003:00020078 00000080H .data$r DATA
0003:000200f8 00000028H .data$rs DATA
0003:00020120 000005f0H .bss DATA
0004:00000000 000003b4H .pdata DATA
0005:00000000 00000060H .rsrc$01 DATA
0005:00000060 00000180H .rsrc$02 DATA
Address Publics by Value Rva+Base Lib:Object
0003:00000000 ?data_arr@@3PAHA 0000000140006000 ccwindowsMain.obj
0002:000003a8 ?Major_version@@3HD 00000001400043a8 ccwindowsMain.obj
0002:000003ac ?Minor_Version@@3MD 00000001400043ac ccwindowsMain.obj
0003:00020020 ?baseSignal@?1??parseSignal@@YAHH@Z@4HA 0000000140026020 ccwindowsMain.obj
0003:00020000 ?base_str_0@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A 0000000140026000 ccwindowsMain.obj
0002:000002c0 ?base_str_0$initializer$@@3P6AXXZEA 00000001400042c0 ccwindowsMain.obj
0002:00000310 ??_C@_0BA@DGGOEDOG@sssssAAAAA00000@ 0000000140004310 ccwindowsMain.obj
0002:000003b0 ??_C@_0BA@GADHIFOA@sssssAAAAA11111@ 00000001400043b0 ccwindowsMain.obj
0002:000003c0 ??_C@_0BA@JKNNMPOK@sssssAAAAA22222@ 00000001400043c0 ccwindowsMain.obj
由以上代码可以看到, Major_version和Minor_Version放在只读数据区(.rdata),baseSignal这个局部静态变量放在.data数据段,而字符串常量放在只读数据段.rdata。
注:这里用 volatile 是为了防止编译器优化。文章来源:https://www.toymoban.com/news/detail-694857.html
可以在 Visual Studio 项目的 连接器 -> 系统 -> 堆栈保留大小 这里按照字节数设置当前程序的默认堆栈大小。文章来源地址https://www.toymoban.com/news/detail-694857.html
到了这里,关于用Visual Studio 2022的.map文件来查看C++变量在内存中的布局情况的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!