⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 谈谈对齐(中) - fmddlmyy的专栏 - csdnblog.htm

📁 講述ARM下的字符數據對齊方式的內容
💻 HTM
📖 第 1 页 / 共 2 页
字号:
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2007/04.aspx">2007年04月(2)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2007/03.aspx">2007年03月(2)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2007/02.aspx">2007年02月(3)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2006/07.aspx">2006年07月(1)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2005/09.aspx">2005年09月(5)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2005/08.aspx">2005年08月(1)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2005/06.aspx">2005年06月(1)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2005/05.aspx">2005年05月(2)</A>
    <LI><A 
    href="http://blog.csdn.net/fmddlmyy/archive/2005/04.aspx">2005年04月(3)</A></LI></UL></DIV><SPAN 
  id=RecentVisitors></SPAN><SPAN id=SubscriptionList>
  <DT>订阅我的博客
  <DD><A href="http://blog.csdn.net/fmddlmyy/Rss.aspx"><IMG alt=XML聚合 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/xml.gif" 
  border=0></A>&nbsp;&nbsp;<A href="http://feeds.feedsky.com/csdn.net/fmddlmyy" 
  target=_blank><IMG alt=FeedSky 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/feedsky.gif" border=0></A>
  <DD><A 
  href="http://www.xianguo.com/subscribe.php?url=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到鲜果 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_xianguo.jpg" border=0></A>
  <DD><A 
  href="http://fusion.google.com/add?feedurl=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到Google 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_google.gif" border=0></A>
  <DD><A 
  href="http://www.zhuaxia.com/add_channel.php?url=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到抓虾 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_zhuaxia.gif" border=0></A>
  <DD><A 
  href="http://www.bloglines.com/sub/http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到BlogLines 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_bloglines.gif" border=0></A>
  <DD><A 
  href="http://add.my.yahoo.com/rss?url=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到Yahoo 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_yahoo.gif" border=0></A>
  <DD><A 
  href="http://rss.gougou.com/find_rss.jsp?url=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到GouGou 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_gougou.gif" border=0></A>
  <DD><A 
  href="http://www.pageflakes.com/subscribe.aspx?url=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到飞鸽 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_pageflakes.gif" border=0></A>
  <DD><A 
  href="http://www.rojo.com/add-subscription?resource=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到Rojo 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_rojo.gif" border=0></A>
  <DD><A 
  href="http://www.newsgator.com/ngs/subscriber/subfext.aspx?url=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到newsgator 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_newsgator.gif" border=0></A>
  <DD><A 
  href="http://www.netvibes.com/subscribe.php?url=http://blog.csdn.net/fmddlmyy/Rss.aspx" 
  target=_blank><IMG alt=订阅到netvibes 
  src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/rss_netvibes.gif" 
  border=0></A></SPAN> </DD></DL></DIV></DIV></DIV>
<DIV id=csdnblog_content>
<DIV class=gutter>
<SCRIPT src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/PrintNotice.js" 
type=text/javascript></SCRIPT>

<DIV class=default_contents>
<DIV class=user_article>
<SCRIPT src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/LoadFeedbackCount.js" 
type=text/javascript></SCRIPT>

<H1><IMG height=16 alt=原创 
src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/authorship.gif" width=15 
border=0>&nbsp;<A 
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/17/2668634.aspx">谈谈对齐(中)</A><CITE 
class=fav_csdnstylebykimi><A class=fav_csdnstylebykimi title=收藏到我的网摘中,并分享给我的朋友 
href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'saveit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();">收藏</A></CITE></H1>
<DIV class=blogstory>
<SCRIPT>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</SCRIPT>
&nbsp; 
<H1>谈谈对齐(中)</H1>
<H3>1.3 变量对齐会带来什么麻烦?</H3>
<P>我在变量对齐问题上吃过一次亏,可以作为本节的一个例子。不过要理解这个例子,读者必须知道ARM 
CPU的一个特点:就是长度为m的基本变量必须放在mn边界上,否则读写时会发生数据访问错误,其中m=2或4。这就是第3节要介绍的数据对齐。</P>
<P>事情是这样,我定义了几个缓冲区(大数组),然后动态分配这些内存。我的错误在于将这些数组定义为字节数组。我的分配算法是按块分配,每个数据块的大小都是4的整数倍。读者能猜到错误产生的原因了吗?</P>
<P>由于我把缓冲区定义为字节数组,编译器就可以把它们放在1n边界。如果缓冲区的起始地址是奇数地址,从缓冲区分配的内存块的起始地址都是奇数地址。如果这些内存块被用于需要按2或4字节对齐的变量,读写时就会发生数据访问错误。如果编译器恰好把这些缓冲区放在4n边界上,问题就不会暴露出来。所以前一次编译可能是好的,但是下一次编译就会发生莫名其妙的错误。调试程序与侦破案件差不多,离犯罪现场越远的凶手就越难发现。在我透过各种表象找到根源之前,吃点苦头是难免的。</P>
<P>解决问题的方法很简单,将缓冲区定义为unsigned 
int(下文记作uint32)的数组,编译器自然会把它们放到4n边界。在嵌入式系统中,我们经常要为任务定义堆栈。这些堆栈通常都是uint32类型的数组。你知道为什么要把它们定义成uint32数组,而不能定义成字节数组了吗?</P>
<H2>2 结构对齐</H2>
<H3>2.1 基本长度</H3>
<P>为了描述方便,我们定义一个基本长度的概念。一个基本变量的基本长度就是它的长度,一个结构变量的基本长度就是结构成员中基本变量的最大长度。前面说过:在默认情况下,结构变量就是按照其基本长度对齐的。</P>
<H3>2.2 对齐</H3>
<P>在默认情况下,可以认为结构的成员按照默认方式对齐,即长度为m的基本变量放在mn边界上,其中m=1,2,4或8。因为要把成员对齐,结构的各成员间就可能出现填充字节,结构的大小可能大于各成员大小之和。例如:</P><PRE>typedef struct St1Tag
{
	char ch1;
	int num1;
	short sh1;
	short sh2;
	char ch2;
} St1;
</PRE>
<P>这个结构的基本长度是4,所以这个结构的变量要放在4n边界。成员num1的基本长度为4,所以也要放在4n边界。成员ch1从4n边界开始,只占1个字节,所以在ch1和num1之间有3个填充字节。</P>
<P>在对齐时,编译器会将结构长度取整到基本长度的整数倍。这样以该结构为基本类型的数组既可以连续排列,每个元素又可以对齐放置。所以,sizeof(St1)的值是16,在St1的最后一个成员ch2后面还有3个填充字节。</P>
<H3>2.3 紧缩</H3>
<P>各编译器都支持结构的紧缩,即连续排列结构的各成员变量,各成员变量之间没有任何填充字节。这时,结构的大小等于各成员变量大小的和。紧缩结构的变量可以放在1n边界,即任意地址边界。</P>
<P>在gcc中可以这样定义紧缩结构:</P><PRE>typedef struct St2Tag
{
	St1 st1;
	char ch2;
}
__attribute__ ((packed)) St2;
</PRE>
<P>armcc是这样的:</P><PRE>typedef __packed struct St2Tag
{
	St1 st1;
	char ch2;
} St2;
</PRE>
<P>VC的写法最麻烦:</P><PRE>#pragma pack(1)
typedef struct St2Tag
{
	St1 st1;
	char ch2;
} St2;
#pragma pack()
</PRE>
<P>如果要同时支持gcc、armcc、VC平台,可以把代码写成这样:</P><PRE>#ifdef __GNUC__
#define GNUC_PACKED	__attribute__ ((packed))
#else
#define GNUC_PACKED
#endif

#ifdef __arm
#define ARM_PACKED	__packed
#else
#define ARM_PACKED
#endif

#ifdef WIN32
#pragma pack(1)
#endif
typedef ARM_PACKED struct St2Tag
{
	St1 st1;
	char ch2;
}
GNUC_PACKED St2;
#ifdef WIN32
#pragma pack()
#endif
</PRE>
<P>其中:__GNUC__是gcc的预定义宏,__arm__是ARM编译器的预定义宏,可以用它们识别当前的编译器。</P>
<H3>2.4 全局设置</H3>
<P>在VC中,有的程序员习惯设置整个工程的struct member 
alignment,这对应于命令行选项“/Zpi”,其中i=1,2,4,8,16。如果将这个值设为1,工程中所有结构都是紧缩排列。紧缩排列会增大代码量,降低结构访问效率。我们应该仅在必要的时候使用紧缩结构。</P>
<P>“/Zp1”是紧缩排列,那么“/Zp2”,“/Zp4”等选项是怎样排列的呢?</P>
<P>设选项“/Zpi”中设定的长度是i,设某个结构成员的基本长度是m,则该结构成员按照m和i中较小的值对齐。例如:如果我们设置了“/Zp2”,则基本长度不大于2的成员按照基本长度对齐,基本长度大于2的成员按照2对齐。</P>
<P>其实,我们不应该使用“/Zp2”这么奇怪的选项,除非有非如此不可的理由。</P>
<H3>2.5 紧缩结构的用途</H3>
<P>其实最常用的结构对齐选项就是:默认对齐和紧缩。在两个程序,或者两个平台之间传递数据时,我们通常会将数据结构设置为紧缩的。这样不仅可以减小通信量,还可以避免对齐带来的麻烦。假设甲乙双方进行跨平台通信,甲方使用了“/Zp2”这么奇怪的对齐选项,而乙方的编译器不支持这种对齐方式,那么乙方就可以理解什么叫欲哭无泪了。</P>
<P>当我们需要一个字节一个字节访问结构数据时,我们通常都会希望结构是紧缩的,这样就不必考虑哪个字节是填充字节了。我们把数据保存到非易失设备时,通常也会采用紧缩结构,既减小存储量,也方便其它程序读出。</P>
<H3>2.6 细节</H3>
<P>最后记录一个小细节。gcc编译器和VC编译器都支持在紧缩结构中包含非紧缩结构,例如前面例子中的St2可以包含非紧缩的St1。但对于ARM编译器而言,紧缩结构包含的其它结构必须是紧缩的。如果紧缩的St2包含了非紧缩的St1,编译时就会报错:</P><PRE>error:  #1031: Definition of "struct St1Tag" in packed "struct St1T2g" must be __packed
</PRE>
<P class="right articalinfo">发表于 @ <A title=permalink 
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/17/2668634.aspx">2008年07月17日 
22:56:00</A>|<A title=评论 
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/17/2668634.aspx#FeedBack">评论(<SPAN 
id=FeedbackCount_2668634>loading...</SPAN>
<SCRIPT type=text/javascript>AddFeedbackCountStack("2668634")</SCRIPT>
)</A>|<A title=编辑 
href="http://writeblog.csdn.net/PostEdit.aspx?entryId=2668634">编辑</A>|<CITE 
class=fav_csdnstylebykimi><A class=fav_csdnstylebykimi title=收藏到我的网摘中,并分享给我的朋友 
href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'saveit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();">收藏</A></CITE></P><SPAN 
id=Post.ascx_ViewPost_PreviousAndNextEntriesDown>
<H3><A 
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/24/2707078.aspx">新一篇:&nbsp;谈谈对齐(下)</A>&nbsp;|&nbsp;<A 
href="http://blog.csdn.net/fmddlmyy/archive/2008/07/16/2663481.aspx">旧一篇:&nbsp;谈谈对齐(上)</A></H3></SPAN></DIV>
<DIV id=Post.ascx_TagAd_palTagAd>
<DIV class=tagadfornews id=csdn_tag_adstyle></DIV></DIV></DIV>
<DIV class=commentslist><SPAN id=Anthem_Post.ascx_Comments_ltlComments__><SPAN 
id=Post.ascx_Comments_ltlComments>
<DIV id=commentslist>
<H3>评论</H3>
<DL class=question>
  <DT><A title="permalink: 回复:谈谈对齐(中)" 
  href="http://blog.csdn.net/fmddlmyy/archive/2008/07/17/2668634.aspx#980391">#</A><A 
  name=980391></A>hongszh&nbsp;发表于2008-12-15 10:29:35&nbsp;&nbsp;IP: 172.17.8.*
  <DD>写的太好了,不过struct声明中,如果同时支持gcc、armcc、VC平台typedef ARM_PACKED struct 
  St2Tag这样写在__GNUC__定义的条件下不可以,__attribute__ ((packed))必须放在struct 的 } 
  的后面,放在typedef后面好像不行。<BR></DD></DL></DIV></SPAN></SPAN></DIV>
<DIV class=spacecommment>
<DIV id=Anthem_Post.ascx_PostComment_CommentUpdatePanel__>
<DIV id=Post.ascx_PostComment_CommentUpdatePanel>
<FIELDSET><LEGEND>发表评论<DFN>只有登录用户才能发表评论!<A 
href="http://passport.csdn.net/member/UserLogin.aspx?from=http://blog.csdn.net/fmddlmyy/archive/2008/07/17/2668634.aspx">登录</A>&nbsp;<A 
href="http://passport.csdn.net/CSDNUserRegister.aspx">注册</A></DFN></LEGEND><EM><IMG 
alt=只有登录用户才能发表评论!请登录或注册 
src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/blog_commentnotice.gif"></EM> 
</FIELDSET> </DIV></DIV></DIV>
<SCRIPT type=text/javascript>
    LoadFeedbackCount();//加载评论
    document.write("<img src='http://counter.csdn.net/pv.aspx?id=24' border=0 width=0 height=0>");// 计数器
    
    </SCRIPT>
</DIV></DIV></DIV>
<DIV id=pubfooter>
<DL>
  <DT>
  <DD>Csdn Blog version 3.1a 
  <DD>Copyright © 吕杰 </DD></DL></DIV></DIV></FORM>
<SCRIPT src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/counter.js" 
type=text/javascript></SCRIPT>
<!-- *** Vdoing Code *** -->
<SCRIPT src="谈谈对齐(中) - fmddlmyy的专栏 - CSDNBlog.files/34089.js" 
type=text/javascript charset=UTF-8></SCRIPT>
<NOSCRIPT><A title="Vdoing StatsX No.34089" href="http://www.vdoing.com/"><IMG 
src="" border=0></A></NOSCRIPT> 
<!-- *** End of Vdoing Code *** --></DIV></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -