<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>西瓜田 &#187; 内存对齐</title>
	<atom:link href="http://blog.thpiano.com/?feed=rss2&#038;tag=%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90" rel="self" type="application/rss+xml" />
	<link>http://blog.thpiano.com</link>
	<description>无复洛城东</description>
	<lastBuildDate>Tue, 19 Jan 2021 03:54:37 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>关于struct的字节对齐</title>
		<link>http://blog.thpiano.com/?p=175</link>
		<comments>http://blog.thpiano.com/?p=175#comments</comments>
		<pubDate>Thu, 03 Nov 2011 13:44:42 +0000</pubDate>
		<dc:creator>suika</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[struct]]></category>
		<category><![CDATA[内存对齐]]></category>

		<guid isPermaLink="false">http://172.18.126.172/blog/?p=175</guid>
		<description><![CDATA[今天的课是由同届的同学来讲的，真是讲得好精彩！ 就我个人感觉来看，已经达到平均水准以上了。稍稍留意了一下，无论是习惯、用语、节奏，都是与我一直接触的老师们别无二样； 作为和他一届的同学真是倍感压力。 啊话题扯远了，临下课前老师借由#pragma提到了struct字节对齐的内容，我也只是不久前刚了解的，真是堪堪赶上教学进度~于是写这篇日志总结顺便再温习一下。 给出这样一段代码： struct test{     char a;     long b; }; void main(){     struct test t1,t2;     memset(&#38;t1,0,sizeof(struct test));     t2.a=0;     t2.b=0;     if (memcmp(&#38;t1,&#38;t2,sizeof(struct test))==0){         printf("yes\n");     }else{         printf("no\n");     }     printf("%d\n",(int)sizeof(struct test)); } 看到声明了两个同类结构体t1,t2，t1使用memset归零，t2则是将成员变量全部归零。在主流编译器上，其结果竟然是no! 最后打印出的struct大小也不是char+long的5字节，而是8字节。 &#160; 究其原因，是因为编译器对struct进行了对齐处理。因而t2只归零了5字节，memcmp会返回不一致。 查看详情，char占据了第一个字节没问题，但是之后的3个字节都空着，直到第4个字节才开始放long。 &#160; 为什么要进行对齐处理呢？ 有些平台上变量不对齐会出错，而有些平台上变量对齐可以提升对内存的读写速度（比如说一个读周期读4个字节，连续读取下每次读都是从偶地址开始。如果long是放在2-5字节的话，就要读两次才行） 对struct对齐处理的规则有两条： 1.每个变量相对头部的偏移量必须是它大小的整数倍，例：char a;long b;  b就要从他体积的整数倍（4的倍数）处开始放，因而放完一个字节的char后，要再空3个字节才可以放b 2.所有变量都存放完毕后，整个struct的体积要能被其最大成员的体积整除 例： struct s1{     char a;   [...]]]></description>
			<content:encoded><![CDATA[<p>今天的课是由同届的同学来讲的，真是讲得好精彩！</p>
<p>就我个人感觉来看，已经达到平均水准以上了。稍稍留意了一下，无论是习惯、用语、节奏，都是与我一直接触的老师们别无二样；</p>
<p>作为和他一届的同学真是倍感压力。</p>
<p>啊话题扯远了，临下课前老师借由#pragma提到了struct字节对齐的内容，我也只是不久前刚了解的，真是堪堪赶上教学进度~于是写这篇日志总结顺便再温习一下。<span id="more-175"></span></p>
<p>给出这样一段代码：</p>
<pre><div>struct test{</div>
<div> <wbr>  <wbr> char a;</wbr></wbr></div>
<div> <wbr>  <wbr> long b;</wbr></wbr></div>
<div>};</div>
<div>void main(){</div>
<div> <wbr>  <wbr> struct test t1,t2;</wbr></wbr></div>
<div> <wbr>  <wbr> memset(&amp;t1,0,sizeof(struct test));</wbr></wbr></div>
<div> <wbr>  <wbr> t2.a=0;</wbr></wbr></div>
<div> <wbr>  <wbr> t2.b=0;</wbr></wbr></div>
<div> <wbr>  <wbr> if (memcmp(&amp;t1,&amp;t2,sizeof(struct test))==0){</wbr></wbr></div>
<div> <wbr>  <wbr>  <wbr>  <wbr> printf("yes\n");</wbr></wbr></wbr></wbr></div>
<div> <wbr>  <wbr> }else{</wbr></wbr></div>
<div> <wbr>  <wbr>  <wbr>  <wbr> printf("no\n");</wbr></wbr></wbr></wbr></div>
<div> <wbr>  <wbr> }</wbr></wbr></div>
<div>    printf("%d\n",(int)sizeof(struct test));</div>
<div>}</div></pre>
<div>看到声明了两个同类结构体t1,t2，t1使用memset归零，t2则是将成员变量全部归零。在主流编译器上，其结果竟然是no!</div>
<div>最后打印出的struct大小也不是char+long的5字节，而是8字节。</div>
<p>&nbsp;</p>
<div>究其原因，是因为编译器对struct进行了对齐处理。因而t2只归零了5字节，memcmp会返回不一致。</div>
<div>查看详情，char占据了第一个字节没问题，但是之后的3个字节都空着，直到第4个字节才开始放long。</div>
<p>&nbsp;</p>
<div>为什么要进行对齐处理呢？</div>
<div>有些平台上变量不对齐会出错，而有些平台上变量对齐可以提升对内存的读写速度（比如说一个读周期读4个字节，连续读取下每次读都是从偶地址开始。如果long是放在2-5字节的话，就要读两次才行）</div>
<div>对struct对齐处理的规则有两条：</div>
<div>1.<span style="color: #0000ff;">每个变量相对头部的偏移量必须是它大小的整数倍</span>，例：char a;long b;  b就要从他体积的整数倍（4的倍数）处开始放，因而放完一个字节的char后，要再空3个字节才可以放b</div>
<div>2.<span style="color: #0000ff;">所有变量都存放完毕后，整个struct的体积要能被其最大成员的体积整除</span></div>
<div>例：</div>
<pre><div>struct s1{</div>
<div>    char a;</div>
<div>    long b;</div>
<div>};</div>
<div>struct s2{</div>
<div>    char a;</div>
<div>    struct s1 s;</div>
<div>    char b;</div>
<div>};</div></pre>
<div>则s1的大小为8字节，<span style="color: #0000ff;">其作为整体时对齐长度不再是体积，而是其内部最大成员即long的4字节</span></div>
<div>s2在地址对齐时，先分配给a一个字节，再空3个字节保证s的偏移量能被4整除，再放s（8个字节），再放一个字节的b</div>
<div>这时的大小为1+3+8+1=13，最后再补3个字节13+3=16，使得16能被最大成员s的对齐长度4整除。</div>
<p>&nbsp;</p>
<div>可以看到，内存对齐是与具体变量的大小息息相关的。</div>
<div>有的变量大小在不同平台上有差异，这个时候可以使用#pragma pack(x)强制定义对齐字节的大小为x</div>
<div>一旦使用了#pragma pack(x)，则每次计算地址对齐时，使用的不再是变量的大小，而是变量大小与x二者的最小值。</div>
<div>比如说先写了#pragma pack(2)，则对于char类型还是按1字节对齐，而对于其他体积大于1字节的变量，都按照2字节对齐</div>
<div>可以使用#pragma pack()换回默认计算方式</div>
<p>&nbsp;</p>
<div>目前的主流编译器都实现了对struct的内存对齐，但并不是所有编译器都支持（手头的老掉牙wintc就不支持，用这个来比赛真是太令人郁闷了）</div>
<div>另外寻求完美的代码高亮方案中，希望能不用插件、复制不会有行号</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.thpiano.com/?feed=rss2&#038;p=175</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
