user-0 提问: c内存中的数据对齐

回复:
user: user-1
content: 引用 25 楼 u014517002 的回复:[quote=引用 23 楼 qq_29120981 的回复:] [quote=引用 19 楼 iGenius_的回复:][quote=引用 18 楼 qq_29120981 的回复:] 这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小 但是栈不是向下增长的吗？那用b的地址减a的地址不是得出了a的大小么？我不知道我理解得对不对[/quote] 根据abc的地址可以得出编译器是依次先后分配cba的内存的，而不是依次分配abc的内存，因为是前者，b的地址是内存首地址a的地址同理，ab地址之差就为b内存的大小。[/quote] 按cba的顺序分配内存？不是按abc吗？只不过是自上到下压栈的时候顺序刚好反过来了[/quote]  抱歉,不当的措辞让楼主误解了,我说的分配指的是内存从低位到高位的加载顺序. 这一张图应该能说明问题

user: user-0
content: 引用 28 楼 qq_29120981 的回复:[quote=引用 25 楼 u014517002 的回复:] [quote=引用 23 楼 qq_29120981 的回复:] [quote=引用 19 楼 iGenius_的回复:][quote=引用 18 楼 qq_29120981 的回复:] 这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小 但是栈不是向下增长的吗？那用b的地址减a的地址不是得出了a的大小么？我不知道我理解得对不对[/quote] 根据abc的地址可以得出编译器是依次先后分配cba的内存的，而不是依次分配abc的内存，因为是前者，b的地址是内存首地址a的地址同理，ab地址之差就为b内存的大小。[/quote] 按cba的顺序分配内存？不是按abc吗？只不过是自上到下压栈的时候顺序刚好反过来了[/quote]  抱歉,不当的措辞让楼主误解了,我说的分配指的是内存从低位到高位的加载顺序. 这一张图应该能说明问题 [/quote] 恩，跟22楼说的一致。我理解了！谢谢你

user: user-2
content: 大小端。。。

user: user-0
content: 引用 22 楼 u012033027 的回复:另外，栈的增长方向向下，不代表保存a的四个字节的顺序是从大到小，反而是从小到大。 有用！我好像有点理解了！多谢

user: user-0
content: 引用 23 楼 qq_29120981 的回复:[quote=引用 19 楼 iGenius_的回复:][quote=引用 18 楼 qq_29120981 的回复:] 这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小 但是栈不是向下增长的吗？那用b的地址减a的地址不是得出了a的大小么？我不知道我理解得对不对[/quote] 根据abc的地址可以得出编译器是依次先后分配cba的内存的，而不是依次分配abc的内存，因为是前者，b的地址是内存首地址a的地址同理，ab地址之差就为b内存的大小。[/quote] 按cba的顺序分配内存？不是按abc吗？只不过是自上到下压栈的时候顺序刚好反过来了

user: user-3
content: 楼主如果想彻底弄明白这个问题，建议参考gcc源代码相关片断。

user: user-1
content: 引用 23 楼 醉花阴柳的回复:[quote=引用 19 楼 iGenius_的回复:][quote=引用 18 楼 qq_29120981 的回复:] 这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小 但是栈不是向下增长的吗？那用b的地址减a的地址不是得出了a的大小么？我不知道我理解得对不对[/quote] 根据abc的地址可以得出编译器是依次先后分配cba的内存的，而不是依次分配abc的内存，因为是前者，b的地址是内存首地址a的地址同理，ab地址之差就为b内存的大小。[/quote] 你的想法是当编译器依次对abc分配内存时才成立的，(这样b-a的地址差为a的大小)而这又与输出地址不合

user: user-1
content: 引用 19 楼 iGenius_的回复:[quote=引用 18 楼 qq_29120981 的回复:] 这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小 但是栈不是向下增长的吗？那用b的地址减a的地址不是得出了a的大小么？我不知道我理解得对不对[/quote] 根据abc的地址可以得出编译器是依次先后分配cba的内存的，而不是依次分配abc的内存，因为是前者，b的地址是内存首地址a的地址同理，ab地址之差就为b内存的大小。

user: user-4
content: 另外，栈的增长方向向下，不代表保存a的四个字节的顺序是从大到小，反而是从小到大。

user: user-4
content: 引用 19 楼 u014517002 的回复:[quote=引用 18 楼 qq_29120981 的回复:] 这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小 但是栈不是向下增长的吗？那用b的地址减a的地址不是得出了a的大小么？我不知道我理解得对不对[/quote]  a, b c是一个函数之内的变量，它们在内存中的分配，跟编译器的策略有关，跟栈的增长方向反而没有多大关系。 0x22fe4c 0x22fe4b 0x22fe44 地址与对应的量之间的关系如下。 栈中间还有一些空白位置，比如a的上面和c的上面，这些地方写了写什么，要问编译器了，不过不必关心。

user: user-3
content: 引用 17 楼 zhao4zhong1 的回复:楼主如果想彻底弄明白这个问题，建议参考gcc源代码相关片断。 理解和讨论之前请先学会如何观察！

user: user-0
content: 引用 18 楼 qq_29120981 的回复:这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小 但是栈不是向下增长的吗？那用b的地址减a的地址不是得出了a的大小么？我不知道我理解得对不对

user: user-1
content: 这和数据对齐好像没关系吧?还有楼主说的根据这三个地址算出a为1字节，这算不出来的，因为只输出了a的首地址，而内存中a又排在高地址，拿a的地址减b的地址只能得出b的大小

user: user-3
content: 计算机组成原理→DOS命令→汇编语言→C语言（不包括C++）、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言（包括C++）、架构……  对学习编程者的忠告： 多用小脑和手，少用大脑、眼睛和嘴，会更快地学会编程！ 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步Debug版对应汇编一行！ 单步Debug版对应汇编千行不如单步Release版对应汇编一行！ 不会单步Release版对应汇编？在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有，然后在IDE中运行。（一般人我不告诉他！）  仅供参考：#include <stdio.h> #define field_offset(s,f) (int)(&(((struct s *)(0))->f)) struct AD  { int a; char b[13]; double c;}; #pragma pack(push) #pragma pack(1) struct A1  { int a; char b[13]; double c;}; #pragma pack(2) struct A2  { int a; char b[13]; double c;}; #pragma pack(4) struct A4  { int a; char b[13]; double c;}; #pragma pack(8) struct A8  { int a; char b[13]; double c;}; #pragma pack(16) struct A16 { int a; char b[13]; double c;}; #pragma pack(pop) int main() {     printf("AD.a %d\n",field_offset(AD,a));     printf("AD.b %d\n",field_offset(AD,b));     printf("AD.c %d\n",field_offset(AD,c));     printf("\n");     printf("A1.a %d\n",field_offset(A1,a));     printf("A1.b %d\n",field_offset(A1,b));     printf("A1.c %d\n",field_offset(A1,c));     printf("\n");     printf("A2.a %d\n",field_offset(A2,a));     printf("A2.b %d\n",field_offset(A2,b));     printf("A2.c %d\n",field_offset(A2,c));     printf("\n");     printf("A4.a %d\n",field_offset(A4,a));     printf("A4.b %d\n",field_offset(A4,b));     printf("A4.c %d\n",field_offset(A4,c));     printf("\n");     printf("A8.a %d\n",field_offset(A8,a));     printf("A8.b %d\n",field_offset(A8,b));     printf("A8.c %d\n",field_offset(A8,c));     printf("\n");     printf("A16.a %d\n",field_offset(A16,a));     printf("A16.b %d\n",field_offset(A16,b));     printf("A16.c %d\n",field_offset(A16,c));     printf("\n");     return 0; } //AD.a 0 //AD.b 4 //AD.c 24 // //A1.a 0 //A1.b 4 //A1.c 17 // //A2.a 0 //A2.b 4 //A2.c 18 // //A4.a 0 //A4.b 4 //A4.c 20 // //A8.a 0 //A8.b 4 //A8.c 24 // //A16.a 0 //A16.b 4 //A16.c 24 // //

user: user-4
content: 你这个问题，只是说明了a, b, c三个变量的分配地址是a > b > c，因为是三个单独变量，怎么分配是编译器确定的，但还不能说明栈的增长问题。 要想看栈的增长方向，最好用函数栈来说明。如下程序 #include <stdio.h> void foo(){   int b;   printf("The address of b: %lx\n", &b); } int main(int argc, char **argv){   int a;   printf("The address of a: %lx\n", &a);   foo(); } main调用foo，所以栈中先有main,再有foo，然后程序的输出为： The address of a: 7fffac5f878c The address of b: 7fffac5f875c b的地址小于a的地址，所以栈是向下增长的。

user: user-5
content: http://www.cnblogs.com/xkfz007/archive/2012/06/22/2558935.html

user: user-0
content: 引用 15 楼 u012033027 的回复:[quote=引用 13 楼 u014517002 的回复:] [quote=引用 12 楼 u012033027 的回复:] [quote=引用 9 楼 u014517002 的回复:] [quote=引用 7 楼 u012033027 的回复:] 你这个问题，只是说明了a, b, c三个变量的分配地址是a > b > c，因为是三个单独变量，怎么分配是编译器确定的，但还不能说明栈的增长问题。 要想看栈的增长方向，最好用函数栈来说明。如下程序 #include <stdio.h> void foo(){   int b;   printf("The address of b: %lx\n", &b); } int main(int argc, char **argv){   int a;   printf("The address of a: %lx\n", &a);   foo(); } main调用foo，所以栈中先有main,再有foo，然后程序的输出为： The address of a: 7fffac5f878c The address of b: 7fffac5f875c b的地址小于a的地址，所以栈是向下增长的。谢谢你的回答，我想问如果栈是向下增长的话，那a（int类型）只占1个byte？[/quote] int类型的a不是只占一个字节，应该是四个，具体要用sizeof(a)来看。 我的程序中输出的只是a的首字节的地址。[/quote] 我指按我最开始提出来的程序运行出来的结果：  #include <stdio.h> int main() {     int a;     char b;     int c;     printf("0x%x\n", &a);     printf("0x%x\n", &b);     printf("0x%x\n", &c); }  结果是： 0x22fe4c 0x22fe4b 0x22fe44 [/quote]  你的也是输出a的地址，跟我的一样的。 不过a的地址是个长整型，printf中应该用%lx，而不是%x。 一般的机器上，a应该占4个字节。[/quote] 我知道它在32位机上应该是4个字节...但是我不懂为什么dev c打印出来的地址那么奇怪，我按照地址的加减得出来的int a;的大小是1个字节啊！望您在您的机器上试试我上面的代码，看能不能理解为什么地址是那样。如果能，请告诉我为什么！谢谢您！

user: user-4
content: 引用 13 楼 u014517002 的回复:[quote=引用 12 楼 u012033027 的回复:] [quote=引用 9 楼 u014517002 的回复:] [quote=引用 7 楼 u012033027 的回复:] 你这个问题，只是说明了a, b, c三个变量的分配地址是a > b > c，因为是三个单独变量，怎么分配是编译器确定的，但还不能说明栈的增长问题。 要想看栈的增长方向，最好用函数栈来说明。如下程序 #include <stdio.h> void foo(){   int b;   printf("The address of b: %lx\n", &b); } int main(int argc, char **argv){   int a;   printf("The address of a: %lx\n", &a);   foo(); } main调用foo，所以栈中先有main,再有foo，然后程序的输出为： The address of a: 7fffac5f878c The address of b: 7fffac5f875c b的地址小于a的地址，所以栈是向下增长的。谢谢你的回答，我想问如果栈是向下增长的话，那a（int类型）只占1个byte？[/quote] int类型的a不是只占一个字节，应该是四个，具体要用sizeof(a)来看。 我的程序中输出的只是a的首字节的地址。[/quote] 我指按我最开始提出来的程序运行出来的结果：  #include <stdio.h> int main() {     int a;     char b;     int c;     printf("0x%x\n", &a);     printf("0x%x\n", &b);     printf("0x%x\n", &c); }  结果是： 0x22fe4c 0x22fe4b 0x22fe44 [/quote]  你的也是输出a的地址，跟我的一样的。 不过a的地址是个长整型，printf中应该用%lx，而不是%x。 一般的机器上，a应该占4个字节。

user: user-0
content: 引用 11 楼 zhao4zhong1 的回复:#define field_offset(s,f)    /*将结构体s的成员f相对结构体开头的字节偏移量以int类型返回*/ \     (int) (                  /*强制转换为int类型                                      */ \         &(                   /*取地址                                                 */ \             (                                                                            \                 (struct s *)(/*强制转换为struct s *类型                               */ \                     0                                                                    \                 )                                                                        \             )->f             /*取前面结构体指针指向的成员f                            */ \         )                                                                                \     )  是将0强制转化为struct s*类型吗？为啥可以这样用？ 那个宏在64位机上要将(int)改成8位的(long)。

user: user-0
content: 引用 12 楼 u012033027 的回复:[quote=引用 9 楼 u014517002 的回复:] [quote=引用 7 楼 u012033027 的回复:] 你这个问题，只是说明了a, b, c三个变量的分配地址是a > b > c，因为是三个单独变量，怎么分配是编译器确定的，但还不能说明栈的增长问题。 要想看栈的增长方向，最好用函数栈来说明。如下程序 #include <stdio.h> void foo(){   int b;   printf("The address of b: %lx\n", &b); } int main(int argc, char **argv){   int a;   printf("The address of a: %lx\n", &a);   foo(); } main调用foo，所以栈中先有main,再有foo，然后程序的输出为： The address of a: 7fffac5f878c The address of b: 7fffac5f875c b的地址小于a的地址，所以栈是向下增长的。谢谢你的回答，我想问如果栈是向下增长的话，那a（int类型）只占1个byte？[/quote] int类型的a不是只占一个字节，应该是四个，具体要用sizeof(a)来看。 我的程序中输出的只是a的首字节的地址。[/quote] 我指按我最开始提出来的程序运行出来的结果：  #include <stdio.h> int main() {     int a;     char b;     int c;     printf("0x%x\n", &a);     printf("0x%x\n", &b);     printf("0x%x\n", &c); }  结果是： 0x22fe4c 0x22fe4b 0x22fe44