置顶 老师参与

对结构的探究

翁恺 发表于2020年04月03日
<p>对结构,我们没有像对数组那样使用sizeof和&amp;这两个工具来探究一下。我们把这个任务留给你。建议可以做这么几个方向的探究:</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>不同的成员变量组合,结构的sizeof如何,是否正好等于全部成员的sizeof之和?</p></li><li><p>结构内的成员之间是否连续,相邻的成员的地址的差是否等于对应的成员的sizeof?<br/></p></li></ol>
71 回复

    1楼

  • 辉县市一中崔静 发表于2020年05月04日
    -6 | 0 | 举报
    辉县市一中崔静 发表于2020年05月04日
    添加评论
  • 2楼

  • Fleedom 发表于2020年05月04日
    24 | 0 | 举报
    <p>结构体的sizeof<br >  这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:<br >  <code class="brush:cpp;toolbar:false" >struct&nbsp;S1   {   char&nbsp;c;   int&nbsp;i;   };</code><br >  问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。<br >  Why为什么受伤的总是我<br >  请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:<br >  S1 s1 = { 'a', 0xFFFFFFFF };<br >  定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么<br >  以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:<br >  0012FF78: 61 CC CC CC FF FF FF FF<br >  发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:<br >  <code class="brush:plain;toolbar:false" >When&nbsp;applied&nbsp;to&nbsp;a&nbsp;structure&nbsp;type&nbsp;or&nbsp;variable,&nbsp;sizeof&nbsp;returns&nbsp;the&nbsp;actual&nbsp;size,&nbsp;which&nbsp;may&nbsp;include&nbsp;padding&nbsp;bytes&nbsp;inserted&nbsp;for&nbsp;alignment.</code>  原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。<br >  为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。<br >  让我们交换一下S1中char与int的位置:<br >  <code class="brush:cpp;toolbar:false" >struct&nbsp;S2   {   int&nbsp;i;   char&nbsp;c;   };</code><br >  看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。<br >  字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:<br >  1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;<br >  2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);<br >  3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。<br >  对于上面的准则,有几点需要说明:<br >  1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。<br >  结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:<br >  #define offsetof(s,m) (size_t)&amp;(((s *)0)-&gt;m)<br >  例如,想要获得S2中c的偏移量,方法为<br >  size_t pos = offsetof(S2, c);https:// pos等于4<br >  2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。<br >  这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):<br >  <code class="brush:cpp;toolbar:false" >struct&nbsp;S3   {   char&nbsp;c1;   S1&nbsp;s;   char&nbsp;c2;   };</code><br >  S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。<br >  c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。<br >  通过上面的叙述,我们可以得到一个公式:<br >  结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:<br >  <img src="https://edu-image.nosdn.127.net/_PhotoUploadUtils_ee7fd200-d035-4bcd-9c7b-abc366c52dc8.png" /></p>
    Fleedom 发表于2020年05月04日
    添加评论
  • 3楼

  • jeffwbf66 发表于2020年05月05日
    2 | 0 | 举报
    <p>DEV-C++测试结果如下:</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;" ><li><p>结构的sizeof和成员的sizeof之和之间有偏差</p></li><li><p>有的结构成员是连续的,有的似乎不连续,有偏移量</p></li></ol><p>以上的结果还没有弄清楚怎么回事</p><p><br ></p><p><img src="https://nos.netease.com/edu-image/692a966408c54df5af19b1d2cd1870d5.png" /></p><p><code class="brush:cpp;toolbar:false" >#include&nbsp;&lt;stdio.h&gt; const&nbsp;int&nbsp;N=5; struct&nbsp;student { char&nbsp;num[7]; char&nbsp;name[20]; double&nbsp;score; }; int&nbsp;main() { int&nbsp;i; struct&nbsp;student&nbsp;s1[N]={{&quot;201203&quot;,&quot;Lihua&quot;,83.5},{&quot;201205&quot;,&quot;Peter&quot;,73.8}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&quot;201202&quot;,&quot;Wanglei&quot;,92.8},{&quot;201201&quot;,&quot;Susan&quot;,69.9},{&quot;201204&quot;,&quot;John&quot;,88.2}}; for(i=0;i&lt;N;i++){ printf(&quot;%s&nbsp;%s&nbsp;%.1f\n&quot;,s1[i].num,s1[i].name,s1[i].score); printf(&quot;%d&nbsp;%d&nbsp;%d&nbsp;%d\n&quot;,sizeof(s1[i].num),sizeof(s1[i].name),sizeof(s1[i].score),sizeof(s1[i])); printf(&quot;%p&nbsp;%p&nbsp;%p\n&quot;,&amp;s1[i].num,&amp;s1[i].name,&amp;s1[i].score); } return&nbsp;0;&nbsp; &nbsp;}</code></p>
    jeffwbf66 发表于2020年05月05日
    添加评论
  • 4楼

  • 书阁下 发表于2020年05月06日
    0 | 0 | 举报
    <p>好</p>
    书阁下 发表于2020年05月06日
    添加评论
  • 5楼

  • 超然居士 发表于2020年05月09日
    0 | 0 | 举报
    <p>结构体的sizeof<br >  这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:<br >  <code class="brush:cpp;toolbar:false" >struct&nbsp;S1   {   char&nbsp;c;   int&nbsp;i;   };</code><br >  问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。<br >  Why为什么受伤的总是我<br >  请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:<br >  S1 s1 = { 'a', 0xFFFFFFFF };<br >  定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么<br >  以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:<br >  0012FF78: 61 CC CC CC FF FF FF FF<br >  发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:<br >  <code class="brush:plain;toolbar:false" >When&nbsp;applied&nbsp;to&nbsp;a&nbsp;structure&nbsp;type&nbsp;or&nbsp;variable,&nbsp;sizeof&nbsp;returns&nbsp;the&nbsp;actual&nbsp;size,&nbsp;which&nbsp;may&nbsp;include&nbsp;padding&nbsp;bytes&nbsp;inserted&nbsp;for&nbsp;alignment.</code>  原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。<br >  为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。<br >  让我们交换一下S1中char与int的位置:<br >  <code class="brush:cpp;toolbar:false" >struct&nbsp;S2   {   int&nbsp;i;   char&nbsp;c;   };</code><br >  看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。<br >  字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:<br >  1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;<br >  2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);<br >  3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。<br >  对于上面的准则,有几点需要说明:<br >  1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。<br >  结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:<br >  #define offsetof(s,m) (size_t)&amp;(((s *)0)-&gt;m)<br >  例如,想要获得S2中c的偏移量,方法为<br >  size_t pos = offsetof(S2, c);https:// pos等于4<br >  2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。<br >  这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):<br >  <code class="brush:cpp;toolbar:false" >struct&nbsp;S3   {   char&nbsp;c1;   S1&nbsp;s;   char&nbsp;c2;   };</code><br >  S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。<br >  c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。<br >  通过上面的叙述,我们可以得到一个公式:<br >  结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:<br >  <img src="https://edu-image.nosdn.127.net/_PhotoUploadUtils_ee7fd200-d035-4bcd-9c7b-abc366c52dc8.png" /></p>
    超然居士 发表于2020年05月09日
    添加评论
  • 6楼

  • mooc49491420110280233 发表于2020年05月10日
    -1 | 0 | 举报
    结构体的sizeof   这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:   struct S1   {   char c;   int i;   };   问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。   Why为什么受伤的总是我   请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:   S1 s1 = { &#39;a&#39;, 0xFFFFFFFF };   定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么   以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:   0012FF78: 61 CC CC CC FF FF FF FF   发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:   When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.  原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。   为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。   让我们交换一下S1中char与int的位置:   struct S2   {   int i;   char c;   };   看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。   字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:   1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;   2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);   3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。   对于上面的准则,有几点需要说明:   1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。   结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:   #define offsetof(s,m) (size_t)&(((s *)0)-&gt;m)   例如,想要获得S2中c的偏移量,方法为   size_t pos = offsetof(S2, c);https:// pos等于4   2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。   这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):   struct S3   {   char c1;   S1 s;   char c2;   };   S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。   c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。   通过上面的叙述,我们可以得到一个公式:   结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:   
    mooc49491420110280233 发表于2020年05月10日
    添加评论
  • 7楼

  • East-o_o 发表于2020年05月10日
    1 | 0 | 举报
    <p>探究结果:</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;" ><li><p>结构的 sizeof 正好等于全部成员的 sizeof 之和;</p></li><li><p>结构内相邻的地址刚好相差一个 sizeof。</p></li></ol><p><code class="brush:cpp;toolbar:false" >#include&nbsp;&lt;stdio.h&gt; struct&nbsp;point&nbsp;{ &nbsp;&nbsp;int&nbsp;x; &nbsp;&nbsp;int&nbsp;y; }; int&nbsp;main(){ &nbsp;&nbsp;struct&nbsp;point&nbsp;z&nbsp;=&nbsp;{5,&nbsp;19&nbsp;}; &nbsp;&nbsp;printf(&quot;--------------------------------------------------\n&quot;); &nbsp;&nbsp;printf(&quot;z&nbsp;=&nbsp;%p\nz.x&nbsp;=&nbsp;%p\tz.y&nbsp;=&nbsp;%p\n&quot;,&nbsp;&amp;z,&nbsp;&amp;z.x,&nbsp;&amp;z.y); &nbsp;&nbsp;printf(&quot;--------------------------------------------------\n&quot;); &nbsp;&nbsp;printf(&quot;z&nbsp;=&nbsp;%d\nz.x&nbsp;=&nbsp;%d\tz.y&nbsp;=&nbsp;%d\n&quot;,&nbsp;sizeof(struct&nbsp;point),&nbsp;sizeof(z.x),&nbsp;sizeof(z.y)); &nbsp;&nbsp;printf(&quot;--------------------------------------------------\n&quot;); &nbsp;&nbsp;return&nbsp;0; }</code></p>
    East-o_o 发表于2020年05月10日
    添加评论
  • 8楼

  • 马昊原 发表于2020年05月11日
    0 | 0 | 举报
    <p>结构的sizeof和成员的sizeof之和之间有偏差</p><p>有的结构成员是连续的,有的似乎不连续,有偏移量</p><p><br ></p>
    马昊原 发表于2020年05月11日
    添加评论
  • 9楼

  • 超然居士 发表于2020年05月11日
    -1 | 0 | 举报
    <p>结构体的sizeof   这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:    struct&nbsp;S1   {   char&nbsp;c;   int&nbsp;i;   };   问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。   Why为什么受伤的总是我   请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:   S1 s1 = { 'a', 0xFFFFFFFF };   定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么   以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:   0012FF78: 61 CC CC CC FF FF FF FF   发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:    When&nbsp;applied&nbsp;to&nbsp;a&nbsp;structure&nbsp;type&nbsp;or&nbsp;variable,&nbsp;sizeof&nbsp;returns&nbsp;the&nbsp;actual&nbsp;size,&nbsp;which&nbsp;may&nbsp;include&nbsp;padding&nbsp;bytes&nbsp;inserted&nbsp;for&nbsp;alignment.   原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。   为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。   让我们交换一下S1中char与int的位置:    struct&nbsp;S2   {   int&nbsp;i;   char&nbsp;c;   };   看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。   字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:   1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;   2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);   3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。   对于上面的准则,有几点需要说明:   1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。   结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:   #define offsetof(s,m) (size_t)&amp;(((s *)0)-&gt;m)   例如,想要获得S2中c的偏移量,方法为   size_t pos = offsetof(S2, c);https:// pos等于4   2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。   这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):    struct&nbsp;S3   {   char&nbsp;c1;   S1&nbsp;s;   char&nbsp;c2;   };   S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。   c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。   通过上面的叙述,我们可以得到一个公式:   结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:   <br ></p>
    超然居士 发表于2020年05月11日
    添加评论
  • 10楼

  • 鲤萌萌 发表于2020年05月12日
    6 | 0 | 举报
    <p><code class="brush:cpp;toolbar:false" >#include&nbsp;&lt;stdio.h&gt; struct&nbsp;student { int&nbsp;No; char&nbsp;Name[10]; double&nbsp;Score; }; int&nbsp;main(void) { struct&nbsp;student&nbsp;student1&nbsp;=&nbsp;{20200512,&nbsp;&quot;LiMing&quot;,&nbsp;99.5}; /*for&nbsp;question&nbsp;1*/ printf(&quot;Struct:&nbsp;%d\n&quot;,&nbsp;sizeof(student1)); printf(&quot;Struct&nbsp;member:&nbsp;%d&nbsp;+&nbsp;%d&nbsp;+&nbsp;%d\n&quot;,&nbsp;sizeof(student1.No),&nbsp;sizeof(student1.Name),&nbsp;sizeof(student1.Score)); /*for&nbsp;question&nbsp;2*/ printf(&quot;Address&nbsp;of&nbsp;member&nbsp;1:&nbsp;%p\n&quot;,&nbsp;&amp;student1.No); printf(&quot;Address&nbsp;of&nbsp;member&nbsp;2:&nbsp;%p\n&quot;,&nbsp;&amp;student1.Name); printf(&quot;Address&nbsp;of&nbsp;member&nbsp;3:&nbsp;%p\n&quot;,&nbsp;&amp;student1.Score); return&nbsp;0; }</code>分别运行了两次的结果:<img src="https://nos.netease.com/edu-image/f31725f78cb3404dbd802cdccde63a07.bmp" /> ,<img src="https://nos.netease.com/edu-image/f21d683eec6c49eb821fe79e1c0794f4.bmp" /></p><p><br /></p><p>可以看到成员2和成员1地址差为4,等于成员1的长度;而成员3和成员2地址差为12,并不等于成员2的长度。</p><p><br /></p><p>/*--------------------------------分割线-----------------------------------*/</p><p>对于问题1:不同的成员变量组合,结构的sizeof并不是正好等于全部成员的sizeof之和,存在偏差。</p><p>对于问题2:结构内的成员之间基本连续,相邻的成员的地址的差并不等于对应的成员的sizeof。</p>
    鲤萌萌 发表于2020年05月12日
    添加评论
  • 11楼

  • bjtu-经管-19241008 发表于2020年05月14日
    -1 | 0 | 举报
    结构体的sizeof   这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:   struct S1   {   char c;   int i;   };   问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。   Why为什么受伤的总是我   请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:   S1 s1 = { &#39;a&#39;, 0xFFFFFFFF };   定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么   以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:   0012FF78: 61 CC CC CC FF FF FF FF   发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:   When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.  原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。   为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。   让我们交换一下S1中char与int的位置:   struct S2   {   int i;   char c;   };   看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。   字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:   1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;   2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);   3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。   对于上面的准则,有几点需要说明:   1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。   结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:   #define offsetof(s,m) (size_t)&(((s *)0)-&gt;m)   例如,想要获得S2中c的偏移量,方法为   size_t pos = offsetof(S2, c);https:// pos等于4   2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。   这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):   struct S3   {   char c1;   S1 s;   char c2;   };   S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。   c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。   通过上面的叙述,我们可以得到一个公式:   结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:   
    bjtu-经管-19241008 发表于2020年05月14日
    添加评论
  • 12楼

  • ______ii______ 发表于2020年05月15日
    1 | 1 | 举报
    <p><img src="https://nos.netease.com/edu-image/672a7d5c21a5443a9f6e4e173b38013c.png" />由运行结果可知,结构体里面的数据类型是遵循“对齐原则”的,从结构体a来看,结构体a只有一个int类型,因此数据长和int一样都是4,我们再看结构体b,结构体b有一个int数据类型和一个double数据类型,如果表面上来看的话,相加应该是4+8=12,然而结果并不是这样,因为对齐原则,结构体b也给int开放了8个长度,因此长度是16,后面的结构体c也是以此类推。</p>
    ______ii______ 发表于2020年05月15日
    • 白昼残留 2020年05月16日
      0 | 举报
      <p>所谓的对齐原则是指,每个成员长度都等于结构体中最长的数据类型?</p>
      白昼残留 发表于2020年05月16日
      0 | 举报
    添加评论
  • 13楼

  • 樊佳斯201903001106 发表于2020年05月16日
    0 | 0 | 举报
    <p>结构的sizeof和成员的sizeof之和之间有偏差</p><p>有的结构成员是连续的,有的似乎不连续,有偏移量</p><p><br ></p>
    樊佳斯201903001106 发表于2020年05月16日
    添加评论
  • 14楼

  • 白昼残留 发表于2020年05月16日
    0 | 0 | 举报
    <p>结构的sizeof大于结构成员的sizeof,在测试一个结构体的情况下,内部成员的地址是连续的。</p><p><img src="https://nos.netease.com/edu-image/51df09d03834442183ab72b28235efcf.jpg" /></p>
    白昼残留 发表于2020年05月16日
    添加评论
  • 15楼

  • 管科191-李斌 发表于2020年05月17日
    1 | 0 | 举报
    <p>结构体的sizeof   这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:   struct S1   {   char c;   int i;   };   问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。   Why为什么受伤的总是我   请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:   S1 s1 = { 'a', 0xFFFFFFFF };   定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么   以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:   0012FF78: 61 CC CC CC FF FF FF FF   发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:   When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.  原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。   为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。   让我们交换一下S1中char与int的位置:   struct S2   {   int i;   char c;   };   看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。   字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:   1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;   2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);   3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。   对于上面的准则,有几点需要说明:   1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。   结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:   #define offsetof(s,m) (size_t)&amp;(((s *)0)-&gt;m)   例如,想要获得S2中c的偏移量,方法为   size_t pos = offsetof(S2, c);https:// pos等于4   2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。   这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):   struct S3   {   char c1;   S1 s;   char c2;   };   S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。   c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。   通过上面的叙述,我们可以得到一个公式:   结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:   </p><p>mooc49491420...</p><p><br ></p>
    管科191-李斌 发表于2020年05月17日
    添加评论
  • 16楼

  • 沉默in 发表于2020年05月17日
    0 | 0 | 举报
    结构体的sizeof   这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:    struct S1   {   char c;   int i;   };   问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。   Why为什么受伤的总是我   请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:   S1 s1 = { &#39;a&#39;, 0xFFFFFFFF };   定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么   以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:   0012FF78: 61 CC CC CC FF FF FF FF   发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:    When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.   原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。   为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。   让我们交换一下S1中char与int的位置:    struct S2   {   int i;   char c;   };   看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。   字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:   1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;   2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);   3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。   对于上面的准则,有几点需要说明:   1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。   结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:   #define offsetof(s,m) (size_t)&(((s *)0)-&gt;m)   例如,想要获得S2中c的偏移量,方法为   size_t pos = offsetof(S2, c);https:// pos等于4   2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。   这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):    struct S3   {   char c1;   S1 s;   char c2;   };   S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。   c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。   通过上面的叙述,我们可以得到一个公式:   结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:   
    沉默in 发表于2020年05月17日
    添加评论
  • 17楼

  • bjtu-19221143杨春艳 发表于2020年05月18日
    0 | 0 | 举报
    结构的sizeof和成员的sizeof之和之间有偏差
    bjtu-19221143杨春艳 发表于2020年05月18日
    添加评论
  • 18楼

  • oh,yes 发表于2020年05月18日
    0 | 0 | 举报
    <p><p>有没有人发现下面两种不同的结构体所占用的字节一样,都是16</p><p><br ></p></p><p> double x;</p><p> int y;</p><p> int p;</p><p><br ></p><p> double x;</p><p> int y;</p><p><br ></p>
    oh,yes 发表于2020年05月18日
    添加评论
  • 19楼

  • 北京交通大学-闵洁 发表于2020年05月19日
    1 | 0 | 举报
    <p>结构的 sizeof 正好等于全部成员的 sizeof 之和;</p><p>结构内相邻的地址刚好相差一个 sizeof。</p><p><br ></p>
    北京交通大学-闵洁 发表于2020年05月19日
    添加评论
  • 20楼

  • Darkening043 发表于2020年05月19日
    0 | 0 | 举报
    <ol class=" list-paddingleft-2" style="list-style-type: decimal;" ><li><p>sizeof(struct name)与struct name中的类型的sizeof之和不一定相等,经过检验发现,sizeof之和等于数据个数倍的最长的数据类型size</p></li><li><p>struct内数据之间不是连续的,短于最长类型的数据的地址会出现跳跃,呈现出的现象似乎表明短的数据类型被“拉长”了</p></li></ol>
    Darkening043 发表于2020年05月19日
    添加评论
点击加载更多