关于内存对齐,这个想不明白。

时间:2022-05-18 10:40:10
下面代码,sizeof(SS)==16,我能理解。
但sizeof(SB)==40,我不能理解。

为什么sizeof(SB)==40?

为什么SB的大小,不是SS大小的整数倍?内存对齐,不是说要填补的吗?



struct SS 
{
double d;
int i;
};

struct SB 
{        
    SS ss;
    char j;  
    double d;  
    int a;   
};  

54 个解决方案

#1


没有人知道?

#2


有些计算机硬件并不能从任何地址访问任何变量,对于某些特定类型的数据,它们只能从特定地址开始存取。所以需要各类型数据按一定规则在内存空间上排列而不是一个接一个的排列,这就是内存(字节)对齐。否则会在存取效率上带来损失。
比如有些平台每次都是从偶地址开始读取数据,那么一个int(32位系统)型存放在偶地址开始的地方,一个读周期即可读出,若是存放于奇地址开始的地方就可能需要两个读周期并对读出的结果的高低字节进行拼凑才能得到该int数据。

结构体字节(内存)对齐一般遵循两个准则:
1.第一个结构成员后的每个结构成员将存储在该成员类型大小和n(1 2 4 8 16)字节边界两者中较小的边界上
2.结构体总大小为最宽基本类型成员大小的整数倍。(如有需要会在最后一个成员之后填充字节)

所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

#3


你看到的是这样?
    SS ss;
    char j;  
    double d;  
    int a;
你认识 SS , 但是 编译器 认识? 它只知道

SS <=>     double d;
           int i;

所以在编译时就相当于:
struct SB 
{        
    double d;
    int i;
    char j;  
    double d;  
    int a;   
};  
计算机当然就会给SB 分配 5*8的内存

#4


所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位 
没依据啊

#5



为什么不是SS char double int?(虽然SS内容是double和int)
 




引用 4 楼  的回复:
所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位 
没依据啊

#6


为什么编译器不认识SS?不是声明且定义了吗?为什么会不认识呢?

引用 3 楼  的回复:
你看到的是这样?
    SS ss;
    char j;  
    double d;  
    int a;
你认识 SS , 但是 编译器 认识? 它只知道

SS <=>     double d;
           int i;

所以在编译时就相当于:
struct SB 
{        
    double d;
    int i;
……

#7


lz的是8对齐吧。vc貌似默认8对齐,你试下改成4对齐看看

#8


我明白了,内存对齐,只对基本类型进行对齐。

这里的基本类型,就是double、int、char等这些。

而SS不是基本类型,所以必须把SS的结构展开,再进行对齐操作。

#9


对于C语言来说,struct里的变量在内存中是按声明的顺序定义的。最终都呈现为 系统的基本类型,如int,double。所以内存排布如3楼所说

#10


引用 4 楼  的回复:
所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位 
没依据啊

32位系统 VS默认的结构体对齐是4字节

#11


引用 3 楼  的回复:
所以在编译时就相当于:
struct SB  
{   
  double d;
  int i;
  char j;   
  double d;   
  int a;   
};   
计算机当然就会给SB 分配 5*8的内存


错!40字节不是这么出来的。而且你这个结构应该是32才对

#12


引用 8 楼  的回复:
我明白了,内存对齐,只对基本类型进行对齐。

这里的基本类型,就是double、int、char等这些。

而SS不是基本类型,所以必须把SS的结构展开,再进行对齐操作。


理解还是有误

SB里的ss是要占16字节的,如果分解开的,只需12字节就够了

#13


引用 12 楼  的回复:
引用 8 楼  的回复:我明白了,内存对齐,只对基本类型进行对齐。

这里的基本类型,就是double、int、char等这些。

而SS不是基本类型,所以必须把SS的结构展开,再进行对齐操作。

理解还是有误

SB里的ss是要占16字节的,如果分解开的,只需12字节就够了

你的结论是基于32位系统的
64位系统下 int类型占8字节
所以第一个double占8字节 第二个int占8字节 第三个char占一字节剩余7字节 第四个double占8字节 7字节不够存 所以补齐7字节(这里是关键 因为若是32位系统 这里补齐的就是3字节) 最后int又占8字节 所以最后即40字节

#14


之所以第二个int占8字节无法确定是不是64位系统是因为通过修改默认对齐方式为8字节也可以达到int类型在32位系统下占8字节的效果。只有char是特别的

#15


引用 10 楼  的回复:
引用 4 楼 的回复:

所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位
没依据啊

32位系统 VS默认的结构体对齐是4字节

vc++6.0 xp系统 运行结果和LZ一样
PS: 这个主要是编译器的vc++6.0 默认是 8字节对齐 
 

#16


引用 14 楼  的回复:
之所以第二个int占8字节无法确定是不是64位系统是因为通过修改默认对齐方式为8字节也可以达到int类型在32位系统下占8字节的效果。只有char是特别的


之所以占8,是因为这个结构里,最大的基本类型double需要8,而整个结构体的大小必须是它的整数倍。没有什么更神秘的原因了

#17


引用 13 楼  的回复:
你的结论是基于32位系统的
64位系统下 int类型占8字节
所以第一个double占8字节 第二个int占8字节 第三个char占一字节剩余7字节 第四个double占8字节 7字节不够存 所以补齐7字节(这里是关键 因为若是32位系统 这里补齐的就是3字节) 最后int又占8字节 所以最后即40字节


对齐有两条准则:
1,起始位置对齐。指定的值,或者成员的长度,取小的那个值。然后,起始位置必须是它的整数倍。
2,总大小必须是最大基本类型的整数倍。
3,char也不例外。

#18


另外,64位上的int,一般也仍然是4位,而不是8位

#19


如果是32位,windows下 结果36
如果64位,windows 结果就是40

条件:vs测试

#20


引用 18 楼  的回复:
另外,64位上的int,一般也仍然是4位,而不是8位

32位int一定是4字节 64位可能是4字节也可能是8字节 所以如果不考虑默认对齐方式的话 int占8字节就一定是64位

所以若是double int char double int顺序 对于32位默认4字节对齐的情况下将占28字节
对于SS char double int顺序 对于32位默认4字节对齐的情况下将占32字节
因为结果是40字节 所以推出 char此时占了8字节 而char后面是double占8字节 所以不用考虑后面了 而char前面若是SS占16字节的情况下自然会使char占8字节 而若是int占4字节的情况下 则该char占4字节即可 同样满足对齐的两条原则。

你一定觉得我考虑double int char double int可笑,因为对于SS来说不管是32位还是64位系统最终都将占16位,其后的char double int对于8字节对齐的结果就是24而无需考虑是多少位系统。

我想说的是,LZ既然只给出这一种顺序,那么其他顺序自然理解了。而这个顺序的关键就是char的位置。所以我第一判断就是char占8字节并且最后的int也占8字节 由此推测的64位系统。


我之所以说char特别是因为即使默认对齐方式为1字节 对于char s = 'a'这种常量初始化情况下也可能因为传递的是指针而变成4字节

#21


http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问

#22


呵呵 #20楼真是想太多了

不信问问,有几个人的程序在sizeof(void*)等于8的时候,sizeof(int)也等于8而不是4的?

#23


引用 22 楼  的回复:
呵呵 #20楼真是想太多了

不信问问,有几个人的程序在sizeof(void*)等于8的时候,sizeof(int)也等于8而不是4的?

一个结构体成员加一个int成员变量的情况下如何?

#24


引用 16 楼  的回复:
引用 14 楼  的回复:之所以第二个int占8字节无法确定是不是64位系统是因为通过修改默认对齐方式为8字节也可以达到int类型在32位系统下占8字节的效果。只有char是特别的

之所以占8,是因为这个结构里,最大的基本类型double需要8,而整个结构体的大小必须是它的整数倍。没有什么更神秘的原因了

当然对于LZ给出的情况 你的这个解答是对的且简单易于理解。

#25


下面是SB的内存分布:
class SB        size(40):
        +---
 0      | SS ss
16      | j
        | <alignment member> (size=7)
24      | d
32      | a
        | <alignment member> (size=4)
        +---
可以看出系统是认识SS的
结构体的总大小为结构体最宽基本类型成员大小的整数倍,注意是基本数据类型,SS不是哦
所以存完a是36,补齐8的倍数,40!

#26


引用 25 楼  的回复:
结构体的总大小为结构体最宽基本类型成员大小的整数倍,注意是基本数据类型


确切地说,应该是 指定的对齐值 和 最宽类型大小 此二者 较小的那个值 的整数倍

#27


引用 23 楼  的回复:
引用 22 楼  的回复:

呵呵 #20楼真是想太多了

不信问问,有几个人的程序在sizeof(void*)等于8的时候,sizeof(int)也等于8而不是4的?

一个结构体成员加一个int成员变量的情况下如何?


没有例外

都是按如下规则
各成员起始于 i*min(pack值,member size)
总大小是 j*min(pack值,largest member size)

#28


你的例子,不够解释我的情况,下面是你给出的例子,如果在struct aa的最后(即代码BB b;的下一行),再加上一个int x,你又该如何分析?结果是多少?

 

typedef struct bb
{
 int id;             //[0]....[3]
 double weight;      //[8].....[15]      原则1
 float height;      //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3
}BB;

typedef struct aa
{
 char name[2];     //[0],[1]
 int  id;         //[4]...[7]          原则1

 double score;     //[8]....[15]    
 short grade;    //[16],[17]        
 BB b;             //[24]......[47]          原则2
}AA;

int main()
{
  AA a;
  cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
  return 0;
}



引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问

#29


我暂时也认为你是对的,最后补齐的,是内部最长的基本类型的整数倍,不是内部最长的类型的整数倍。

因此,最后补齐double的整数倍,不是补齐SS的整数倍。


引用 25 楼  的回复:
下面是SB的内存分布:
class SB        size(40):
        +---
 0      | SS ss
16      | j
        | <alignment member> (size=7)
24      | d
32      | a
        | <alignment member> (size=4)
        +--……

#30


struct SS 
{
double d;  
int i;     
};

struct SB 
{        
SS ss;     //[0-15]
char j;    //[16]
double d;  //[24-31]
int a;     //[32-35]
};  //36按8取整 40

#31


引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问

++

#32


SB里面拆开SS来看,其实是5个double的空间

#33


程序编写题
有一个二进制文件,其内容描述如下:
● 文件的内容是一个序列
● 序列中的每一个元素的数据类型是 int
● 序列已经从小到大排序
● 序列中有重复的元素
● 序列中的元素有可能是不连续的
● 序列的长度不是固定的,有可能很短,也可能非常长(例如文件大于1GB)
● 一个序列示例: 3,6,6,7,8,9,11
此时文件的前sizeof(int)个字节是3,接着的sizeof(int)个字节是6,依此类推。
现给定任意一个int类型的数 x(x在文件中不一定存在), 需要在文件中找一个数
y,y必须满足下列条件:
● y <= x
● 在所有满足小于等于x的数中, y在文件中的偏移量是最大的
用C语言完成下面的函数定义:
/**
* 在文件中查找一个数的左邻居 (文件的格式如以上所描述)
* @param path 文件路径名
* @param x 用于比较的数
* @param y 输出参数, 在文件中找到的x的左邻居(小于等于x的最大数,
* 并且其在文件中的偏移量也是满足条件中的数中最大的)
* @param offset 输出参数, y在文件中的偏移量
* 如果在文件中没有找到符合条件的数, 或者出错,把 *offset置为-1。
*/
void find_left_neighbor(const char *path, int x, int *y, long *offset)
{
}
要求如下:
● 使用折半查找方法(二分法)。
● 请尽量从程序正确性、程序执行效率、程序健壮性、代码可读性方面完善您的代码,
使其达到能够在实际项目中使用的程度。
帮助信息──文件操作的相关C库函数:
FILE *fopen(const char *path, const char *mode);
int fclose(FILE *fp);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
The whence argument to fseek() can be SEEK_SET, SEEK_END, or SEEK_CUR.

#34


最好给我加点注释都

#35


引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测):

struct test
{
    char aaa[3];
    short val;
    char ccc[3];
};

#36


引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测,VS2005默认对齐):

struct test
{
    char aaa[3];
    short val;
    char ccc[3];
};

#37


9
引用 36 楼  的回复:
引用 21 楼  的回复:

http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测,VS2005默认对齐):
C/C++ code

struct test
{
 ……

#38


错了,是10,学习了
引用 37 楼  的回复:
9
引用 36 楼  的回复:

引用 21 楼  的回复:

http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测,VS2005默认对齐):
C/C++ co……

#39


引用 25 楼  的回复:
下面是SB的内存分布:
class SB size(40):
  +---
 0 | SS ss
16 | j
  | <alignment member> (size=7)
24 | d
32 | a
  | <alignment member> (size=4)
  +---
可以看出系统是认识SS的
结构体的总大小为结构体最宽基本类型成员大小的整数倍,注意是基本数据类型……


终结此帖子,其他人都在唧唧歪歪的扯开话题

#40




$ cat a.c
struct S1
{
    double d;
    int i;
};

struct S2
{
    struct S1 ss;
    char j;
    double d;
    int a;
};

#include <stdio.h>

int main(void)
{
    printf("%d\n", sizeof (struct S1));
    printf("%d\n", sizeof (struct S2));
    return 0;
}
$ make && ./main.out
make: `main.out' is up to date.
12
28
$


#41


这个看具体实现吧

#42


引用 38 楼  的回复:
错了,是10,学习了


恩,是10字节。判断最终结果对与不对,只要看结果是否是最长成员整数倍就好了。我写的那个结构,最长的是short,所以9不可能对。

win32结构对齐的问题,比如我们选了8字节对齐,MS的编译器会把成员依次往8字节里放。放的时候也有讲究,地址会选择该成员的整数倍,比如是char,则选0、1、2、3、4等等,short会选0、2、4、6,而不会选择1、3、5,如果是int,则会选择0、4、8为开始地址(这里的地址都是相对结构开头)。当前8字节放不下了,则放下一个8字节开始。

以8个字节为单位对齐的话,最后可能剩一些空间,如果这些空间是最长成员的整数倍,则会被截断。

就这么简单,win32下验证过多次了。

#43


按照俺的说法,在win32、MS编译器环境下,非单字节对齐的话,结构的长度如果是奇数,那么这个结构必定只包含char,不可能包含short或其他偶数长度的成员。

不信可以测试一下,嘿嘿。

#44


系统:WindowsXP
IDE:VS2008

还是用程序说话吧!

class AA
{
public:
double d;
HWND _h1;
int i;
int i2;
int i3;
short int short_i;
wchar_t wstr;
wchar_t wstr2;
char str;

};
class CC 
{
public:
char str;
AA a;
int i;
double d;
};
int main()
{
vector<int> stack_int; //C++内置类型
AA a;
stack_int.push_back(sizeof(a.d));
stack_int.push_back(sizeof(a._h1));
stack_int.push_back(sizeof(a.i));
stack_int.push_back(sizeof(a.i2));
stack_int.push_back(sizeof(a.i3));
stack_int.push_back(sizeof(a.short_i));
stack_int.push_back(sizeof(a.wstr));
stack_int.push_back(sizeof(a.wstr2));
stack_int.push_back(sizeof(a.str));
a.d=1;
a._h1=(HWND)2;
//CC c;
//stack_int.push_back(sizeof(c.str));
//stack_int.push_back(sizeof(c.i));
//stack_int.push_back(sizeof(c.d));

vector<int> stack_other; //自定义类型
//stack_other.push_back(sizeof(c.a));


int temp = 0 ,result = 0 ,max4=0;
for (vector<int>::iterator iter = stack_int.begin();
iter !=stack_int.end();++iter)
{
if(*iter%4 == 0)
{
if(temp != 0)
{
result += temp / (*iter) * (*iter);
if (temp%(*iter) != 0)
{
result += *iter;
}
temp = 0;
}else if(*iter > max4 && max4 != 0){
result -= max4;
result += *iter;
}

result+=*iter;

max4 = max4 > *iter ? max4 : *iter;
}else
{
temp+=*iter;
}
cout<<*iter<<"  "<<result<<endl;
}

if(temp != 0)
result += temp;


cout<<"\n内置类型对齐结果:"<<result<<endl;

//内置类型以外的类型
temp=0;
for (vector<int>::iterator iter = stack_other.begin();
iter !=stack_other.end();++iter)
{
temp += *iter;
}

result += temp;

cout<<"\n内置类型以外的类型:"<<temp<<"  ->  "<<result<<endl;

cout<<"\n对齐系数:"<<max4<<endl;

if(max4 != 0 && (result % max4) != 0)
{
result = (result / max4 + 1) * max4;
}
cout<<"\nsizeof(原型) "<<sizeof(AA)<<"\n最终对齐结果(类/结构):"<<result<<endl;
system("pause");
return 0;
}

#45


SS 并不是基本类型,所以你不能用SS的倍数去计算

#46


学习来了,内存对其表示不是很懂

#47


SS的基本结构被分开带入SB了
SB就为:
struct SB 
{        
    double d;
    int i;
    char j;  
    double d;  
    int a;   
};  

VS默认是8字节对齐,那么结果就是:40

#48


上面一个帖子弄错了,再发一帖
struct SB  
{   
   SS ss;   占用内存位置:0-15
   char j;   占用内存位置:16
  double d;   占用内存位置:24-31
  int a;    占用内存位置:32-35
}; 

上面结构体大小是36了,整体对齐后就是 40.

VS默认是8字节对齐,那么结果就是:40

#49


看编译器还有系统
32位一般是4字节对齐,VC没有试过,64位的话应该是8位对齐

#50


内存对齐,是编译器的实现决定的。内存对齐,能够减少数据读取总线的次数。
有时候,程序编译,会报总线错误,就是由于内存未对齐引发的错误。

关于这个,可以看看 《深入理解C++对象模型》这本介绍和编译器实现相关的书,能够更好的理解C++,类的实现,设计等等。

关于对齐的讨论以及sizeof 见: http://blog.csdn.net/wzb56/article/details/7694517

#1


没有人知道?

#2


有些计算机硬件并不能从任何地址访问任何变量,对于某些特定类型的数据,它们只能从特定地址开始存取。所以需要各类型数据按一定规则在内存空间上排列而不是一个接一个的排列,这就是内存(字节)对齐。否则会在存取效率上带来损失。
比如有些平台每次都是从偶地址开始读取数据,那么一个int(32位系统)型存放在偶地址开始的地方,一个读周期即可读出,若是存放于奇地址开始的地方就可能需要两个读周期并对读出的结果的高低字节进行拼凑才能得到该int数据。

结构体字节(内存)对齐一般遵循两个准则:
1.第一个结构成员后的每个结构成员将存储在该成员类型大小和n(1 2 4 8 16)字节边界两者中较小的边界上
2.结构体总大小为最宽基本类型成员大小的整数倍。(如有需要会在最后一个成员之后填充字节)

所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

#3


你看到的是这样?
    SS ss;
    char j;  
    double d;  
    int a;
你认识 SS , 但是 编译器 认识? 它只知道

SS <=>     double d;
           int i;

所以在编译时就相当于:
struct SB 
{        
    double d;
    int i;
    char j;  
    double d;  
    int a;   
};  
计算机当然就会给SB 分配 5*8的内存

#4


所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位 
没依据啊

#5



为什么不是SS char double int?(虽然SS内容是double和int)
 




引用 4 楼  的回复:
所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位 
没依据啊

#6


为什么编译器不认识SS?不是声明且定义了吗?为什么会不认识呢?

引用 3 楼  的回复:
你看到的是这样?
    SS ss;
    char j;  
    double d;  
    int a;
你认识 SS , 但是 编译器 认识? 它只知道

SS <=>     double d;
           int i;

所以在编译时就相当于:
struct SB 
{        
    double d;
    int i;
……

#7


lz的是8对齐吧。vc貌似默认8对齐,你试下改成4对齐看看

#8


我明白了,内存对齐,只对基本类型进行对齐。

这里的基本类型,就是double、int、char等这些。

而SS不是基本类型,所以必须把SS的结构展开,再进行对齐操作。

#9


对于C语言来说,struct里的变量在内存中是按声明的顺序定义的。最终都呈现为 系统的基本类型,如int,double。所以内存排布如3楼所说

#10


引用 4 楼  的回复:
所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位 
没依据啊

32位系统 VS默认的结构体对齐是4字节

#11


引用 3 楼  的回复:
所以在编译时就相当于:
struct SB  
{   
  double d;
  int i;
  char j;   
  double d;   
  int a;   
};   
计算机当然就会给SB 分配 5*8的内存


错!40字节不是这么出来的。而且你这个结构应该是32才对

#12


引用 8 楼  的回复:
我明白了,内存对齐,只对基本类型进行对齐。

这里的基本类型,就是double、int、char等这些。

而SS不是基本类型,所以必须把SS的结构展开,再进行对齐操作。


理解还是有误

SB里的ss是要占16字节的,如果分解开的,只需12字节就够了

#13


引用 12 楼  的回复:
引用 8 楼  的回复:我明白了,内存对齐,只对基本类型进行对齐。

这里的基本类型,就是double、int、char等这些。

而SS不是基本类型,所以必须把SS的结构展开,再进行对齐操作。

理解还是有误

SB里的ss是要占16字节的,如果分解开的,只需12字节就够了

你的结论是基于32位系统的
64位系统下 int类型占8字节
所以第一个double占8字节 第二个int占8字节 第三个char占一字节剩余7字节 第四个double占8字节 7字节不够存 所以补齐7字节(这里是关键 因为若是32位系统 这里补齐的就是3字节) 最后int又占8字节 所以最后即40字节

#14


之所以第二个int占8字节无法确定是不是64位系统是因为通过修改默认对齐方式为8字节也可以达到int类型在32位系统下占8字节的效果。只有char是特别的

#15


引用 10 楼  的回复:
引用 4 楼 的回复:

所以按照你给出的double int char double int数据顺序就是40(可以推测出你的系统是64位)

不可以推测出系统是64位
没依据啊

32位系统 VS默认的结构体对齐是4字节

vc++6.0 xp系统 运行结果和LZ一样
PS: 这个主要是编译器的vc++6.0 默认是 8字节对齐 
 

#16


引用 14 楼  的回复:
之所以第二个int占8字节无法确定是不是64位系统是因为通过修改默认对齐方式为8字节也可以达到int类型在32位系统下占8字节的效果。只有char是特别的


之所以占8,是因为这个结构里,最大的基本类型double需要8,而整个结构体的大小必须是它的整数倍。没有什么更神秘的原因了

#17


引用 13 楼  的回复:
你的结论是基于32位系统的
64位系统下 int类型占8字节
所以第一个double占8字节 第二个int占8字节 第三个char占一字节剩余7字节 第四个double占8字节 7字节不够存 所以补齐7字节(这里是关键 因为若是32位系统 这里补齐的就是3字节) 最后int又占8字节 所以最后即40字节


对齐有两条准则:
1,起始位置对齐。指定的值,或者成员的长度,取小的那个值。然后,起始位置必须是它的整数倍。
2,总大小必须是最大基本类型的整数倍。
3,char也不例外。

#18


另外,64位上的int,一般也仍然是4位,而不是8位

#19


如果是32位,windows下 结果36
如果64位,windows 结果就是40

条件:vs测试

#20


引用 18 楼  的回复:
另外,64位上的int,一般也仍然是4位,而不是8位

32位int一定是4字节 64位可能是4字节也可能是8字节 所以如果不考虑默认对齐方式的话 int占8字节就一定是64位

所以若是double int char double int顺序 对于32位默认4字节对齐的情况下将占28字节
对于SS char double int顺序 对于32位默认4字节对齐的情况下将占32字节
因为结果是40字节 所以推出 char此时占了8字节 而char后面是double占8字节 所以不用考虑后面了 而char前面若是SS占16字节的情况下自然会使char占8字节 而若是int占4字节的情况下 则该char占4字节即可 同样满足对齐的两条原则。

你一定觉得我考虑double int char double int可笑,因为对于SS来说不管是32位还是64位系统最终都将占16位,其后的char double int对于8字节对齐的结果就是24而无需考虑是多少位系统。

我想说的是,LZ既然只给出这一种顺序,那么其他顺序自然理解了。而这个顺序的关键就是char的位置。所以我第一判断就是char占8字节并且最后的int也占8字节 由此推测的64位系统。


我之所以说char特别是因为即使默认对齐方式为1字节 对于char s = 'a'这种常量初始化情况下也可能因为传递的是指针而变成4字节

#21


http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问

#22


呵呵 #20楼真是想太多了

不信问问,有几个人的程序在sizeof(void*)等于8的时候,sizeof(int)也等于8而不是4的?

#23


引用 22 楼  的回复:
呵呵 #20楼真是想太多了

不信问问,有几个人的程序在sizeof(void*)等于8的时候,sizeof(int)也等于8而不是4的?

一个结构体成员加一个int成员变量的情况下如何?

#24


引用 16 楼  的回复:
引用 14 楼  的回复:之所以第二个int占8字节无法确定是不是64位系统是因为通过修改默认对齐方式为8字节也可以达到int类型在32位系统下占8字节的效果。只有char是特别的

之所以占8,是因为这个结构里,最大的基本类型double需要8,而整个结构体的大小必须是它的整数倍。没有什么更神秘的原因了

当然对于LZ给出的情况 你的这个解答是对的且简单易于理解。

#25


下面是SB的内存分布:
class SB        size(40):
        +---
 0      | SS ss
16      | j
        | <alignment member> (size=7)
24      | d
32      | a
        | <alignment member> (size=4)
        +---
可以看出系统是认识SS的
结构体的总大小为结构体最宽基本类型成员大小的整数倍,注意是基本数据类型,SS不是哦
所以存完a是36,补齐8的倍数,40!

#26


引用 25 楼  的回复:
结构体的总大小为结构体最宽基本类型成员大小的整数倍,注意是基本数据类型


确切地说,应该是 指定的对齐值 和 最宽类型大小 此二者 较小的那个值 的整数倍

#27


引用 23 楼  的回复:
引用 22 楼  的回复:

呵呵 #20楼真是想太多了

不信问问,有几个人的程序在sizeof(void*)等于8的时候,sizeof(int)也等于8而不是4的?

一个结构体成员加一个int成员变量的情况下如何?


没有例外

都是按如下规则
各成员起始于 i*min(pack值,member size)
总大小是 j*min(pack值,largest member size)

#28


你的例子,不够解释我的情况,下面是你给出的例子,如果在struct aa的最后(即代码BB b;的下一行),再加上一个int x,你又该如何分析?结果是多少?

 

typedef struct bb
{
 int id;             //[0]....[3]
 double weight;      //[8].....[15]      原则1
 float height;      //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3
}BB;

typedef struct aa
{
 char name[2];     //[0],[1]
 int  id;         //[4]...[7]          原则1

 double score;     //[8]....[15]    
 short grade;    //[16],[17]        
 BB b;             //[24]......[47]          原则2
}AA;

int main()
{
  AA a;
  cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
  return 0;
}



引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问

#29


我暂时也认为你是对的,最后补齐的,是内部最长的基本类型的整数倍,不是内部最长的类型的整数倍。

因此,最后补齐double的整数倍,不是补齐SS的整数倍。


引用 25 楼  的回复:
下面是SB的内存分布:
class SB        size(40):
        +---
 0      | SS ss
16      | j
        | <alignment member> (size=7)
24      | d
32      | a
        | <alignment member> (size=4)
        +--……

#30


struct SS 
{
double d;  
int i;     
};

struct SB 
{        
SS ss;     //[0-15]
char j;    //[16]
double d;  //[24-31]
int a;     //[32-35]
};  //36按8取整 40

#31


引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问

++

#32


SB里面拆开SS来看,其实是5个double的空间

#33


程序编写题
有一个二进制文件,其内容描述如下:
● 文件的内容是一个序列
● 序列中的每一个元素的数据类型是 int
● 序列已经从小到大排序
● 序列中有重复的元素
● 序列中的元素有可能是不连续的
● 序列的长度不是固定的,有可能很短,也可能非常长(例如文件大于1GB)
● 一个序列示例: 3,6,6,7,8,9,11
此时文件的前sizeof(int)个字节是3,接着的sizeof(int)个字节是6,依此类推。
现给定任意一个int类型的数 x(x在文件中不一定存在), 需要在文件中找一个数
y,y必须满足下列条件:
● y <= x
● 在所有满足小于等于x的数中, y在文件中的偏移量是最大的
用C语言完成下面的函数定义:
/**
* 在文件中查找一个数的左邻居 (文件的格式如以上所描述)
* @param path 文件路径名
* @param x 用于比较的数
* @param y 输出参数, 在文件中找到的x的左邻居(小于等于x的最大数,
* 并且其在文件中的偏移量也是满足条件中的数中最大的)
* @param offset 输出参数, y在文件中的偏移量
* 如果在文件中没有找到符合条件的数, 或者出错,把 *offset置为-1。
*/
void find_left_neighbor(const char *path, int x, int *y, long *offset)
{
}
要求如下:
● 使用折半查找方法(二分法)。
● 请尽量从程序正确性、程序执行效率、程序健壮性、代码可读性方面完善您的代码,
使其达到能够在实际项目中使用的程度。
帮助信息──文件操作的相关C库函数:
FILE *fopen(const char *path, const char *mode);
int fclose(FILE *fp);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
The whence argument to fseek() can be SEEK_SET, SEEK_END, or SEEK_CUR.

#34


最好给我加点注释都

#35


引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测):

struct test
{
    char aaa[3];
    short val;
    char ccc[3];
};

#36


引用 21 楼  的回复:
http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测,VS2005默认对齐):

struct test
{
    char aaa[3];
    short val;
    char ccc[3];
};

#37


9
引用 36 楼  的回复:
引用 21 楼  的回复:

http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测,VS2005默认对齐):
C/C++ code

struct test
{
 ……

#38


错了,是10,学习了
引用 37 楼  的回复:
9
引用 36 楼  的回复:

引用 21 楼  的回复:

http://blog.csdn.net/hairetz/article/details/4084088

以前总结的,第二条应该可以解答你的疑问


看你混论坛也挺久了,没想到也犯错,俺心理平衡啦。考你一下,下面的结构长度为多少?(win32环境,不许敲代码直接目测,VS2005默认对齐):
C/C++ co……

#39


引用 25 楼  的回复:
下面是SB的内存分布:
class SB size(40):
  +---
 0 | SS ss
16 | j
  | <alignment member> (size=7)
24 | d
32 | a
  | <alignment member> (size=4)
  +---
可以看出系统是认识SS的
结构体的总大小为结构体最宽基本类型成员大小的整数倍,注意是基本数据类型……


终结此帖子,其他人都在唧唧歪歪的扯开话题

#40




$ cat a.c
struct S1
{
    double d;
    int i;
};

struct S2
{
    struct S1 ss;
    char j;
    double d;
    int a;
};

#include <stdio.h>

int main(void)
{
    printf("%d\n", sizeof (struct S1));
    printf("%d\n", sizeof (struct S2));
    return 0;
}
$ make && ./main.out
make: `main.out' is up to date.
12
28
$


#41


这个看具体实现吧

#42


引用 38 楼  的回复:
错了,是10,学习了


恩,是10字节。判断最终结果对与不对,只要看结果是否是最长成员整数倍就好了。我写的那个结构,最长的是short,所以9不可能对。

win32结构对齐的问题,比如我们选了8字节对齐,MS的编译器会把成员依次往8字节里放。放的时候也有讲究,地址会选择该成员的整数倍,比如是char,则选0、1、2、3、4等等,short会选0、2、4、6,而不会选择1、3、5,如果是int,则会选择0、4、8为开始地址(这里的地址都是相对结构开头)。当前8字节放不下了,则放下一个8字节开始。

以8个字节为单位对齐的话,最后可能剩一些空间,如果这些空间是最长成员的整数倍,则会被截断。

就这么简单,win32下验证过多次了。

#43


按照俺的说法,在win32、MS编译器环境下,非单字节对齐的话,结构的长度如果是奇数,那么这个结构必定只包含char,不可能包含short或其他偶数长度的成员。

不信可以测试一下,嘿嘿。

#44


系统:WindowsXP
IDE:VS2008

还是用程序说话吧!

class AA
{
public:
double d;
HWND _h1;
int i;
int i2;
int i3;
short int short_i;
wchar_t wstr;
wchar_t wstr2;
char str;

};
class CC 
{
public:
char str;
AA a;
int i;
double d;
};
int main()
{
vector<int> stack_int; //C++内置类型
AA a;
stack_int.push_back(sizeof(a.d));
stack_int.push_back(sizeof(a._h1));
stack_int.push_back(sizeof(a.i));
stack_int.push_back(sizeof(a.i2));
stack_int.push_back(sizeof(a.i3));
stack_int.push_back(sizeof(a.short_i));
stack_int.push_back(sizeof(a.wstr));
stack_int.push_back(sizeof(a.wstr2));
stack_int.push_back(sizeof(a.str));
a.d=1;
a._h1=(HWND)2;
//CC c;
//stack_int.push_back(sizeof(c.str));
//stack_int.push_back(sizeof(c.i));
//stack_int.push_back(sizeof(c.d));

vector<int> stack_other; //自定义类型
//stack_other.push_back(sizeof(c.a));


int temp = 0 ,result = 0 ,max4=0;
for (vector<int>::iterator iter = stack_int.begin();
iter !=stack_int.end();++iter)
{
if(*iter%4 == 0)
{
if(temp != 0)
{
result += temp / (*iter) * (*iter);
if (temp%(*iter) != 0)
{
result += *iter;
}
temp = 0;
}else if(*iter > max4 && max4 != 0){
result -= max4;
result += *iter;
}

result+=*iter;

max4 = max4 > *iter ? max4 : *iter;
}else
{
temp+=*iter;
}
cout<<*iter<<"  "<<result<<endl;
}

if(temp != 0)
result += temp;


cout<<"\n内置类型对齐结果:"<<result<<endl;

//内置类型以外的类型
temp=0;
for (vector<int>::iterator iter = stack_other.begin();
iter !=stack_other.end();++iter)
{
temp += *iter;
}

result += temp;

cout<<"\n内置类型以外的类型:"<<temp<<"  ->  "<<result<<endl;

cout<<"\n对齐系数:"<<max4<<endl;

if(max4 != 0 && (result % max4) != 0)
{
result = (result / max4 + 1) * max4;
}
cout<<"\nsizeof(原型) "<<sizeof(AA)<<"\n最终对齐结果(类/结构):"<<result<<endl;
system("pause");
return 0;
}

#45


SS 并不是基本类型,所以你不能用SS的倍数去计算

#46


学习来了,内存对其表示不是很懂

#47


SS的基本结构被分开带入SB了
SB就为:
struct SB 
{        
    double d;
    int i;
    char j;  
    double d;  
    int a;   
};  

VS默认是8字节对齐,那么结果就是:40

#48


上面一个帖子弄错了,再发一帖
struct SB  
{   
   SS ss;   占用内存位置:0-15
   char j;   占用内存位置:16
  double d;   占用内存位置:24-31
  int a;    占用内存位置:32-35
}; 

上面结构体大小是36了,整体对齐后就是 40.

VS默认是8字节对齐,那么结果就是:40

#49


看编译器还有系统
32位一般是4字节对齐,VC没有试过,64位的话应该是8位对齐

#50


内存对齐,是编译器的实现决定的。内存对齐,能够减少数据读取总线的次数。
有时候,程序编译,会报总线错误,就是由于内存未对齐引发的错误。

关于这个,可以看看 《深入理解C++对象模型》这本介绍和编译器实现相关的书,能够更好的理解C++,类的实现,设计等等。

关于对齐的讨论以及sizeof 见: http://blog.csdn.net/wzb56/article/details/7694517