﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-gifty</title><link>http://www.cppblog.com/gifty/</link><description /><language>zh-cn</language><lastBuildDate>Sat, 04 Apr 2026 05:38:52 GMT</lastBuildDate><pubDate>Sat, 04 Apr 2026 05:38:52 GMT</pubDate><ttl>60</ttl><item><title>全局/静态变量内存布局</title><link>http://www.cppblog.com/gifty/archive/2011/05/07/145897.html</link><dc:creator>gifty</dc:creator><author>gifty</author><pubDate>Sat, 07 May 2011 07:52:00 GMT</pubDate><guid>http://www.cppblog.com/gifty/archive/2011/05/07/145897.html</guid><wfw:comment>http://www.cppblog.com/gifty/comments/145897.html</wfw:comment><comments>http://www.cppblog.com/gifty/archive/2011/05/07/145897.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gifty/comments/commentRss/145897.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gifty/services/trackbacks/145897.html</trackback:ping><description><![CDATA[<h3>测试程序：</h3> <p>#include <iostream>  <p>#include <string.h>  <p>using namespace std;  <p>static int gs_num[53];  <p>char g_buf1[190];  <p>char g_buf2[232];  <p>char g_buf3[] = "That's really a test!";  <p>static char gs_buf1[233];  <p>class Base  <p>{  <p>public:  <p>Base()  <p>{  <p>memset(buf, 1, 100);  <p>}  <p>~Base()  <p>{  <p>}  <p>private:  <p>char buf[100];  <p>};  <p>Base g_base;  <p>static Base gs_base;  <p>void func()  <p>{  <p>static int s1[10];  <p>static char s2[16] = "fs";  <p>static int s3[20] = {15};  <p>s1[10] = 3;  <p>int a = s1[0]+ s2[0];  <p>}  <p>int main()  <p>{  <p>static int a[10] = {3};  <p>static int b[10] = {4};  <p>//func();  <p>static Base base;  <p>static char temp[100];  <p>static char temp1[39];  <p>static Base base1;  <p>int c = a[0] + b[0];  <p>cout<<temp1<<endl;  <p>gs_buf1[0] = 'a';  <p>return 0;  <p>}  <h3>内存布局</h3> <p>在main入口处设置断点后内存布局如下：  <p>0x8049160 <g_buf3>: 1952540756 1914729255 1819042149 543236217  <p>0x8049170 <g_buf3+16>: 1953719668 33 0 0  <p>0x8049180 <_ZZ4mainE1b>: 4 0 0 0  <p>0x8049190 <_ZZ4mainE1b+16>: 0 0 0 0  <p>0x80491a0 <_ZZ4mainE1b+32>: 0 0 0 0  <p>0x80491b0: 0 0 0 0  <p>0x80491c0 <_ZZ4mainE1a>: 3 0 0 0  <p>0x80491d0 <_ZZ4mainE1a+16>: 0 0 0 0  <p>0x80491e0 <_ZZ4mainE1a+32>: 0 0 29542 0  <p>0x80491f0 <_ZZ4funcvE2s2+8>: 0 0 0 0  <p>0x8049200 <_ZSt4cout@@GLIBCXX_3.4>: 3086816908 3086816928 6 0  <p>0x8049210 <_ZSt4cout@@GLIBCXX_3.4+16>: 4098 0 0 0  <p>0x8049220 <_ZSt4cout@@GLIBCXX_3.4+32>: 0 0 0 0  <p>0x8049230 <_ZSt4cout@@GLIBCXX_3.4+48>: 0 0 0 0  <p>0x8049240 <_ZSt4cout@@GLIBCXX_3.4+64>: 0 0 0 0  <p>0x8049250 <_ZSt4cout@@GLIBCXX_3.4+80>: 0 0 0 0  <p>0x8049260 <_ZSt4cout@@GLIBCXX_3.4+96>: 0 0 8 134517288  <p>0x8049270 <_ZSt4cout@@GLIBCXX_3.4+112>: 3086833084 0 0 3086827968  <p>0x8049280 <_ZSt4cout@@GLIBCXX_3.4+128>: 3086829728 3086830428 3086830420 0  <p>0x8049290 <dtor_idx.5708>: 0 0 0 0  <p>0x80492a0 <g_buf1>: 0 0 0 0  <p>0x80492b0 <g_buf1+16>: 0 0 0 0  <p>0x80492c0 <g_buf1+32>: 0 0 0 0  <p>0x80492d0 <g_buf1+48>: 0 0 0 0  <p>0x80492e0 <g_buf1+64>: 0 0 0 0  <p>0x80492f0 <g_buf1+80>: 0 0 0 0  <p>0x8049300 <g_buf1+96>: 0 0 0 0  <p>0x8049310 <g_buf1+112>: 0 0 0 0  <p>0x8049320 <g_buf1+128>: 0 0 0 0  <p>0x8049330 <g_buf1+144>: 0 0 0 0  <p>0x8049340 <g_buf1+160>: 0 0 0 0  <p>0x8049350 <g_buf1+176>: 0 0 0 0  <p>0x8049360 <g_buf2>: 0 0 0 0  <p>0x8049370 <g_buf2+16>: 0 0 0 0  <p>0x8049380 <g_buf2+32>: 0 0 0 0  <p>0x8049390 <g_buf2+48>: 0 0 0 0  <p>0x80493a0 <g_buf2+64>: 0 0 0 0  <p>0x80493b0 <g_buf2+80>: 0 0 0 0  <p>0x80493c0 <g_buf2+96>: 0 0 0 0  <p>0x80493d0 <g_buf2+112>: 0 0 0 0  <p>0x80493e0 <g_buf2+128>: 0 0 0 0  <p>0x80493f0 <g_buf2+144>: 0 0 0 0  <p>0x8049400 <g_buf2+160>: 0 0 0 0  <p>0x8049410 <g_buf2+176>: 0 0 0 0  <p>0x8049420 <g_buf2+192>: 0 0 0 0  <p>0x8049430 <g_buf2+208>: 0 0 0 0  <p>0x8049440 <g_buf2+224>: 0 0 0 0  <p>0x8049450: 0 0 0 0  <p>0x8049460 <g_base>: 16843009 16843009 16843009 16843009  <p>0x8049470 <g_base+16>: 16843009 16843009 16843009 16843009  <p>0x8049480 <g_base+32>: 16843009 16843009 16843009 16843009  <p>0x8049490 <g_base+48>: 16843009 16843009 16843009 16843009  <p>0x80494a0 <g_base+64>: 16843009 16843009 16843009 16843009  <p>0x80494b0 <g_base+80>: 16843009 16843009 16843009 16843009  <p>0x80494c0 <g_base+96>: 16843009 0 0 0  <p>0x80494d0: 0 0 0 0  <p>0x80494e0 <_ZL7gs_base>: 16843009 16843009 16843009 16843009  <p>0x80494f0 <_ZL7gs_base+16>: 16843009 16843009 16843009 16843009  <p>0x8049500 <_ZL7gs_base+32>: 16843009 16843009 16843009 16843009  <p>0x8049510 <_ZL7gs_base+48>: 16843009 16843009 16843009 16843009  <p>0x8049520 <_ZL7gs_base+64>: 16843009 16843009 16843009 16843009  <p>0x8049530 <_ZL7gs_base+80>: 16843009 16843009 16843009 16843009  <p>0x8049540 <_ZL7gs_base+96>: 16843009 0 0 0  <p>0x8049550 <_ZGVZ4mainE5base1>: 0 0 0 0  <p>0x8049560 <_ZL7gs_buf1>: 0 0 0 0  <p>0x8049570 <_ZL7gs_buf1+16>: 0 0 0 0  <p>0x8049580 <_ZL7gs_buf1+32>: 0 0 0 0  <p>0x8049590 <_ZL7gs_buf1+48>: 0 0 0 0  <p>0x80495a0 <_ZL7gs_buf1+64>: 0 0 0 0  <p>---Type <return> to continue, or q <return> to quit---  <p>0x80495b0 <_ZL7gs_buf1+80>: 0 0 0 0  <p>0x80495c0 <_ZL7gs_buf1+96>: 0 0 0 0  <p>0x80495d0 <_ZL7gs_buf1+112>: 0 0 0 0  <p>0x80495e0 <_ZL7gs_buf1+128>: 0 0 0 0  <p>0x80495f0 <_ZL7gs_buf1+144>: 0 0 0 0  <p>0x8049600 <_ZL7gs_buf1+160>: 0 0 0 0  <p>0x8049610 <_ZL7gs_buf1+176>: 0 0 0 0  <p>0x8049620 <_ZL7gs_buf1+192>: 0 0 0 0  <p>0x8049630 <_ZL7gs_buf1+208>: 0 0 0 0  <p>0x8049640 <_ZL7gs_buf1+224>: 0 0 0 0  <p>0x8049650: 0 0 0 0  <p>0x8049660 <_ZZ4mainE5base1>: 0 0 0 0  <p>0x8049670 <_ZZ4mainE5base1+16>: 0 0 0 0  <p>0x8049680 <_ZZ4mainE5base1+32>: 0 0 0 0  <p>0x8049690 <_ZZ4mainE5base1+48>: 0 0 0 0  <p>0x80496a0 <_ZZ4mainE5base1+64>: 0 0 0 0  <p>0x80496b0 <_ZZ4mainE5base1+80>: 0 0 0 0  <p>0x80496c0 <_ZZ4mainE5base1+96>: 0 0 0 0  <p>0x80496d0: 0 0 0 0  <p>0x80496e0 <_ZZ4mainE5temp1>: 0 0 0 0  <p>0x80496f0 <_ZZ4mainE5temp1+16>: 0 0 0 0  <p>0x8049700 <_ZZ4mainE5temp1+32>: 0 0 0 0  <p>0x8049710: 0 0 0 0  <p>0x8049720 <_ZZ4mainE4base>: 0 0 0 0  <p>0x8049730 <_ZZ4mainE4base+16>: 0 0 0 0  <p>0x8049740 <_ZZ4mainE4base+32>: 0 0 0 0  <p>0x8049750 <_ZZ4mainE4base+48>: 0 0 0 0  <p>0x8049760 <_ZZ4mainE4base+64>: 0 0 0 0  <p>0x8049770 <_ZZ4mainE4base+80>: 0 0 0 0  <p>0x8049780 <_ZZ4mainE4base+96>: 0 0 0 0  <p>0x8049790: 0 0 0 0  <p>0x80497a0 <_ZZ4funcvE2s1>: 0 0 0 0  <p>0x80497b0 <_ZZ4funcvE2s1+16>: 0 0 0 0  <p>0x80497c0 <_ZZ4funcvE2s1+32>: 0 0 0 0  <p>0x80497d0: 0 0 0 0  <p>0x80497e0: 0 0 0 0  <p>0x80497f0: 0 0 0 0  <p>0x8049800: 0 0 0 0  <p>0x8049810: 0 0 0 0  <p>0x8049820: 0 0 0 0  <p>0x8049830: 0 0 0 0  <p>0x8049840: 0 0 0 0  <p>0x8049850: 0 0 0 0  <h3>分析结果：</h3> <p>全局变量与静态变量的唯一区别在于链接属性，全局变量为外部链接属性，全局静态变量（类内部的静态变量）为内部链接属性，函数内部的静态变量无链接属性。  <p>注：对于类内部的静态变量，类名相当于一个命名空间，而全局静态变量的命名空间为：：（全局命名空间），所以它们本质上无差别!  <p>全局变量和静态变量内存布局基本相同，这里一并考虑。  <p>全局/静态变量的内存分配主要是遵循一个大的原则，将初始化的和未初始化的变量分开存放，初始化的变量被放在全局数据区，未初始化的变量放在BSS段，这样有一个好处，BSS段在文件中是没有大小的，只有一个地址，所有未初始化的全局静态变量都指向这个地址，这样可以减小文件的大小。而在运行时，才会为BSS段分配内存空间，并且全部初始化为0，所以未初始化的全局/静态变量载入内存后，默认值为0。  <p>然后我们看内存布局：  <p>前面4个变量依次是，g_buf3，_ZZ4mainE1b，_ZZ4mainE1a和_ZZ4funcvE2s2，编译器在编译时为了防止名称冲突，会对变量函数名进行名称修饰，linux下可用c++filt工具进行还原。  <p>还原后的变量依次是：  <p>g_buf3，main函数中的静态变量b、a和func中的静态变量s2。  <p>这4个是初始化了的全局/静态变量，所以被放在全局初始化区，这里我们得出以下几点结论。  <p>1、可以发现s2和s3都被初始化了，可是只有s2被分配内存空间，而s3并未分配内存空间，这是因为linux中为静态变量分配内存是根据该变量是否被使用来判断的，如果一个静态变量定义后，未发现它被其它变量引用了，将不会为其分配内存空间。  <p>2、对于全局变量，不管它是否被使用了，都会为其分配内存空间。  <p>3、在函数中的静态变量，在内存中的顺序恰恰和它们在函数中的声明顺序相反（目前尚不知这样做的原因）。  <p>这里有一个疑问，g_base和gs_base这两个变量被初始化了，为什么它们被放在未初始化的全局数据区。这是因为g_base和gs_base这两个变量是在运行时通过调用构造函数被初始化的，在编译时我们是无法知道它们的值的，所以在编译时它们也被放在了BSS段。所以这里得出结论：  <p>4、全局/静态类变量在内存中被放在未初始化数据区。  <p>下面我们看看未初始化数据区里面的变量，依次是  <p>g_buf1、g_buf2、g_base、gs_base、main函数的base1、temp1、base，func函数的s1。  <p>可以看到g_base、gs_base值不为0，而base1，base的值为0，因为我的断点是在main函数入口处设置的，所以全局类变量的构造函数已被调用过了，而main函数内的类变量的构造函数尚未调用，但是它们的内存空间已被分配，这印证了以上结论4。</p>  <img src ="http://www.cppblog.com/gifty/aggbug/145897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gifty/" target="_blank">gifty</a> 2011-05-07 15:52 <a href="http://www.cppblog.com/gifty/archive/2011/05/07/145897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GCC预编译头技术</title><link>http://www.cppblog.com/gifty/archive/2011/05/02/145487.html</link><dc:creator>gifty</dc:creator><author>gifty</author><pubDate>Mon, 02 May 2011 07:50:00 GMT</pubDate><guid>http://www.cppblog.com/gifty/archive/2011/05/02/145487.html</guid><wfw:comment>http://www.cppblog.com/gifty/comments/145487.html</wfw:comment><comments>http://www.cppblog.com/gifty/archive/2011/05/02/145487.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gifty/comments/commentRss/145487.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gifty/services/trackbacks/145487.html</trackback:ping><description><![CDATA[<blockquote style="MARGIN-RIGHT: 0px" dir="ltr">
<p style="TEXT-ALIGN: left">最近在弄GCC的预编译头，用C++开发工程最难以忍受的就是乌龟似地的编译速度，用VC开发工程的时候，VC会默认帮我们引入预编译头，那么GCC呢？其实GCC也是支持预编译头得， <a href="http://lych.yo2.cn/articles/浅谈gcc预编译头技术.html ">http://lych.yo2.cn/articles/浅谈gcc预编译头技术.html </a>这篇文章就详细讲解了如何GCC下预编译头得一些知识, 所以具体如何在GCC中加入预编译头,大家可以参考这篇文章。
<br/></p>
<p>在给GCC添加预编译头时也遇到了一些问题，并且对C++/C的编译有了一些新的认识！</p>
<p><br/>
很多在linux下写程序的人都应该看过《和我一起写Makefile》这篇文章，里面讲过如何利用GCC的-MM选项自动生成依赖：</p>
<p><br/>
%.d: %.cpp
<br/>
@$(GPP) -MM $(INCLUDE) $< > $@.tmp;\
<br/>
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.tmp > $@;\
<br/>
rmf <a href="mailto:$@.tmp">$@.tmp</a></p>
<p><br/>
这里利用了一个模式规则，将CPP文件依赖的头文件写到一个.d文件中，执行Makefile时我们只需要include这些.d文件，GCC就会根据里面的依赖关系来生成对应的.o文件了！
<br/>
但是实际上GCC的自动推导能力非常强大，我们其实只需要写下一条这样的模式就可以了，
<br/>
%.o:%.cpp
<br/>
@$(GPP) $(CPPFLAGS) $< $(INCLUDE)</p>
<p><br/>
GCC就会自动推导出CPP文件所需要依赖的头文件进行编译了！</p>
<p><br/>
如果你在自己的工程中加入了预编译头，你就必须使用下面一种模式。
<br/>
举个例子，比如你们工程开发了一些基础库，已经比较稳定了，除了一些少量的BUG FIX外，很少需要修改，当你通过源码形式引用的时候，你当然不希望每次编译的时候都去编译
<br/>
这些基础库，如是你决定将他们加入预编译头中去，但是当你使用第一种方式写Makefile的时候，你发现被你加入到预编译头中的头文件还是被重复编译了，因为-MM选项会把你CPP文件
<br/>
依赖的非系统头文件全部放在对应的.d文件中。但是当你使用第二种Makefile时，GCC看到一个预编译头后，他不会按照常规的方式将它展开，而是回去寻找对应的.gch文件，然后进行编译，
<br/>
如果你想一探究竟的话,编译加上-H选项就可以看出其中的差异了！</p>
<p>这样生成的预编译头如果要使用的话，需要和编译CPP文件使用相同的选项，否则后出现一些奇怪的编译错误，我的做法是写一个预编译头得模式：</p>
<p>%.h.gch:%.h
<br/>
$(GPP) $(CPPFLAGS) $< $(INCLUDE)</p>
</blockquote>
     <img src ="http://www.cppblog.com/gifty/aggbug/145487.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gifty/" target="_blank">gifty</a> 2011-05-02 15:50 <a href="http://www.cppblog.com/gifty/archive/2011/05/02/145487.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>