数据对齐的问题

silly_sinba 2008-10-08 12:55:14
看了一些公司的面试题目,关于数据对齐部分,有些不懂,请各位看看:

class A
{
public:
double d;//8
float a;//4
int b;//4
char c;//1
};

class B
{
public:
float f;//4
char p;//1
int adf[3];//12
};

class C
{
};

class D
{
public:
D(){cout<<"dddd"<<endl;}
~D(){cout<<"_____"<<endl;}
virtual void f(int){cout<<"fff_int"<<endl;}
virtual void f(double){cout<<"fff_double"<<endl;}
void g(int i = 10){cout<<"ggg "<<i<<endl;}
};

int main(){
cout<<sizeof(A);//输出24

cout<<sizeof(B);
//我做的答案是以12来对齐,得到24,给的正确答案是20。请懂得同学帮忙解释下为什么以4字节对齐~

cout<<sizeof(C);//答案说是1字节,空的类都有1字节,那么请问this指针都有4字节啊?!怎么保存this指针呢?

cout<<sizeof(D);
//答案给的4字节,因为只有一个指针,请问这个指针是什么?
//虚表指针还是this指针,如果是this指针,那么请看上一个问题。

return 0;
}

...全文
331 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
太乙 2008-10-08
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 silly_sinba 的回复:]
上面的原因已经明白了哈~ 果然是只要没超出段域 就可以放
但是下面的程序很晕 :

#include <iostream>
using namespace std;
class A
{
public :
int a;
short int b;
int c;
short int d;
private:

};

int main()
{

cout < <sizeof(A) < <endl;//输出16

int a;
short int b;
int c;
short int d;
cout < <"a: " < <hex < <&a < <" " < <sizeof(a) < <endl;
cout < <"b: "…
[/Quote]

第二个那个10是十六进制!
devil_zuiai 2008-10-08
  • 打赏
  • 举报
回复
cout < <sizeof(B);
//我做的答案是以12来对齐,得到24,给的正确答案是20。请懂得同学帮忙解释下为什么以4字节对齐~
===================================
默认应该是以4对齐,
假设分配从0x0000开始
1.第一个float由于float是4,所以对齐为4,由于0x0000%4=0,所以分配0x0000~0x0003给float f

2.第二个char由于char是1,所以对齐为1, 由于0x0004%1=0,所以分配0x0004给char p

3.第三个int由于int是4,所以对齐为4,由于0x0005%4 != 0,所以要对齐,由于0x0008%4 = 0,所以从
0x0008分配3个int,所以分配空间为0x0008~0x0013

所以总共是0x0000~0x0013为20,
由于20%4 = 0, 所以不需要再对齐,所以答案是20.
silly_sinba 2008-10-08
  • 打赏
  • 举报
回复
上面的原因已经明白了哈~ 果然是只要没超出段域 就可以放
但是下面的程序很晕 :

#include<iostream>
using namespace std;
class A
{
public :
int a;
short int b;
int c;
short int d;
private:

};

int main()
{

cout<<sizeof(A)<<endl;//输出16

int a;
short int b;
int c;
short int d;
cout<<"a: "<<hex<<&a<<" "<<sizeof(a)<<endl;
cout<<"b: "<<hex<<&b<<" "<<sizeof(b)<<endl;
cout<<"c: "<<hex<<&c<<" "<<sizeof(c)<<endl;
cout<<"d: "<<hex<<&d<<" "<<sizeof(d)<<endl<<endl;

cout<<sizeof(A)<<endl;//输出10

A test;
cout<<"a: "<<hex<<&test.a<<" "<<endl;
cout<<"b: "<<hex<<&test.b<<" "<<endl;
cout<<"c: "<<hex<<&test.c<<" "<<endl;
cout<<"d: "<<hex<<&test.d<<" "<<endl;
return 0;
}


cout<<sizeof(A)<<endl;两次的输入不一样……这又是为什么呢?
silly_sinba 2008-10-08
  • 打赏
  • 举报
回复
哈哈 谢谢hqin6 同学 我去验证你说的一句话去了——
“存放规则:
按最大的类型对齐:
不能跨段域

然后依次放入:


果然是依次的 我以为编译器会优化 结果没有优化,只交换了下定义变量的先后,下面两个运行的结果不同……
class A
{
public :
int a;
short int b;
int c;
short int d;

};

sizieof(A) 是16字节;
××××××××××××××××××××××××××××××××××××××××××××××××××××××

class A
{
public :
int a;
int c;
short int b;
short int d;

};

sizieof(A) 是12字节;


把main函数也贴出来,可以运行看看:

int main()
{
cout<<sizeof(A)<<endl;

A test;
cout<<"a: "<<hex<<&test.a<<" "<<endl;
cout<<"c: "<<hex<<&test.c<<" "<<endl;
cout<<"b: "<<hex<<&test.b<<" "<<endl;
cout<<"d: "<<hex<<&test.d<<" "<<endl;
return 0;
}

季昂 2008-10-08
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 hqin6 的回复:]
C/C++ codelz记住,变量的存放是不能跨段域的!

如果在一个段能存放下,就存,不能就得空着

像你说的:classE
{public:floatf;//4shortintsi;//2shortintsii;//2};

因为si和sii能在一个段域里存放下,所以就放一个段域了

如果sii是int型的,那么就是3*4=12因为si后面的俩字节得空着,sii不能跨段!
[/Quote]
顶一个,我也想知道为什么空类的大小是1
chenzhp 2008-10-08
  • 打赏
  • 举报
回复
Win32平台下的微软C编译器(cl.exe for 80×86)的对齐策略:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
备注:编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能被该基本数据类型所整除的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
备注:为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。
备注:结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就必须在最后填充几个字节以达到本条要求。
jiaoxiaogu 2008-10-08
  • 打赏
  • 举报
回复
csdn的各位大侠果真雷厉风行,才高八斗啊~~
以后就决定在这里混了~
太乙 2008-10-08
  • 打赏
  • 举报
回复

lz记住,变量的存放是不能跨段域的!

如果在一个段能存放下,就存,不能就得空着

像你说的:

class E
{
public:
float f;//4
short int si;//2
short int sii;//2
};

因为si和sii能在一个段域里存放下,所以就放一个段域了

如果sii是int型的,那么就是3*4=12

因为si后面的俩字节得空着,sii不能跨段!
太乙 2008-10-08
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 silly_sinba 的回复:]
谢谢楼上同学 前面几位的意思我都明白了,只是请问hqin6同学

如果是

class E
{
public:
float f;//4
short int si;//2
short int sii;//2
};

那么sizeof(E)又应该是几字节呢? 按你的算法是4*3=12
但是我看书上好像是先加起来 如果不是4的整倍数,则再补几个字节,补成4的整倍数。那么这个就是8字节。

我的现在的系统上没有c++编译器 能不能帮我运行下看看sizeof(E)是多少呢?!
[/Quote]


按float类型补齐,也就是4字节补齐
而short int是俩字节
所以,存放的时候是:

前四字节是f,接着俩字节是si,然后又是sii俩字节。


存放规则:
按最大的类型对齐:
不能跨段域

然后依次放入:

比如:

int a
char b
int c

那么放的时候就是:

按四个字节对齐

a占四个字节
b占俩字节
c占四个字节,而由于b占了俩字节,那么b后面 的俩字节就得空着,c不能跨段域

所以是
a占四个字节
b占俩字节,后面俩字节空,也是四个字节
c占四个字节

所以是3*4


silly_sinba 2008-10-08
  • 打赏
  • 举报
回复
我同学刚帮我运行了 结果是8 那么是先加起来 再按边界补够 对吗?
silly_sinba 2008-10-08
  • 打赏
  • 举报
回复
谢谢楼上同学 前面几位的意思我都明白了,只是请问hqin6同学

如果是

class E
{
public:
float f;//4
short int si;//2
short int si;//2
};

那么sizeof(E)又应该是几字节呢? 按你的算法是4*3=12
但是我看书上好像是先加起来 如果不是4的整倍数,则再补几个字节,补成4的整倍数。那么这个就是8字节。

我的现在的系统上没有c++编译器 能不能帮我运行下看看sizeof(E)是多少呢?!
jia_xiaoxin 2008-10-08
  • 打赏
  • 举报
回复
1.对齐规则规定每个结构成员将存储在成员中类型大小最大的类型的大小或 n 字节边界(其中 n 为 1、2、4、8 或 16)两者中较小的一个边界上,
n 字节边界一般默认为4,所以8+4+4+4 = 20
而2008下的默认n字节边界为8,所以你计算出来的就为 8+4+4+8 = 24;

2.当类内存在虚函数时,才会存储虚函数表的指针。一般的this指针是添加到成员函数的参数列表上,所以不会增加大小。
zhangzhao123 2008-10-08
  • 打赏
  • 举报
回复
sizeof(B)中是以最大字节类型对齐,即int数组 4个字节 总字节:4+4+3*4=20
太乙 2008-10-08
  • 打赏
  • 举报
回复



#include<iostream>
using namespace std;
class A
{
public:
double d;//8
float a;//4
int b;//4
char c;//1
};

class B
{
public:
float f;//4
char p;//1
int adf[3];//12
};

class C
{
};

class D
{
public:
D(){cout <<"dddd" <<endl;}
~D(){cout <<"_____" <<endl;}
virtual void f(int){cout <<"fff_int" <<endl;}
virtual void f(double){cout <<"fff_double" <<endl;}
void g(int i = 10){cout <<"ggg " <<i <<endl;}
};

int main(){
cout <<sizeof(A)<<endl;//输出24
以double型所占字节数对齐,也就是8字节对齐,
第一个八字节是d,第二个八字节是a、b,第三个八字节是c。后面有空位,但是对齐,所以空着就空着,3*8=24

cout <<sizeof(B)<<endl;
//我做的答案是以12来对齐,得到24,给的正确答案是20。请懂得同学帮忙解释下为什么以4字节对齐~
以float型对齐,也就是4字节对齐
int数组相当于三个,那么就是4*5=20


cout <<sizeof(C)<<endl;//答案说是1字节,空的类都有1字节,那么请问this指针都有4字节啊?!怎么保存this指针呢?

汗~~~~~~~~~~

cout <<sizeof(D)<<endl;
//答案给的4字节,因为只有一个指针,请问这个指针是什么?
//虚表指针还是this指针,如果是this指针,那么请看上一个问题。

虚函数表指针

return 0;
}





  • 打赏
  • 举报
回复
sizeof(B):类的对齐按照结构体中最大的元素类型对齐,所以按照sizeof(int)对齐
sizeof(C):C++标准规定,空的类要补为sizeof = 1,也就是补一个char的成员;至于this指针,实际上是不存在的,只是方便程序员来操作而产生的对象地址的别名。用汇编来看,直接传递的就是对象地址。
sizeof(D): 由于有了虚函数,所以有了虚函数表,那4个字节当然就是虚函数表指针了。
yyyapple 2008-10-08
  • 打赏
  • 举报
回复
得出这样的答案估计默认是按8字节对齐的

改成#pragma pack(4)答案是
20
20
1
4
xkyx_cn 2008-10-08
  • 打赏
  • 举报
回复
class B中,对齐是按照数组中的元素类型大小,而不是数组的大小;如果有结构体或者类元素,也要按其最大的元素类型,而不是整个结构体或者类

this指针是对象的地址,而不是类的地址,1个字节只是编译器的实现

64,651

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧