sizeof 用法

系统 1487 0

结构体对齐的具体含义 ( #pragma pack )

#pragma pack (4)
class TestB
{
public:
int aa;
char a;
short b;
char c;
};
int nSize = sizeof(TestB);
  这里 nSize 结果为 12 ,在预料之中。

  现在去掉第一个成员变量为如下代码:
#pragma pack (4)
class TestC
{
public:
char a;
short b;
char c;
};
int nSize = sizeof(TestC);
  按照正常的填充方式 nSize 的结果应该是 8 ,为什么结果显示 nSize 6 呢?

事实上,很多人对 #pragma pack 的理解是错误的。
#pragma pack
规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为 0 的地方,以后每个数据成员的对齐,按照 #pragma pack 指定的数值和这个数据成员自身长度中, 比较小 的那个进行。
也就是说,当 #pragma pack 的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
结构整体 的对齐,则按照结构体中最大的数据成员 和 #pragma pack 指定值 之间,较小的那个进行。

具体解释
#pragma pack (4)
class TestB
{
public:
int aa; // 第一个成员,放在 [0,3] 偏移的位置,
char a; // 第二个成员,自身长为 1 #pragma pack (4), 取小值,也就是 1 ,所以这个成员按一字节对齐,放在偏移 [4] 的位置。
short b; // 第三个成员,自身长 2 #pragma pack (4) ,取 2 ,按 2 字节对齐,所以放在偏移 [6,7] 的位置。
char c; // 第四个,自身长为 1 ,放在 [8] 的位置。
};
这个类实际占据的内存空间是 9 字节
类之间的对齐, 是按照类内部最大的成员的长度 ,和 #pragma pack 规定的值之中 较小的一个对 齐的。
所以这个例子中,类之间对齐的长度是 min(sizeof(int),4) ,也就是 4
9
按照 4 字节圆整的结果是 12 ,所以 sizeof(TestB) 12

起始倍数曰对齐,

体内对齐,自身 pra 取小值,

体间对齐,最大 pra 取小值,

体间上取整


如果
#pragma pack (2)
class TestB
{
public:
int aa; // 第一个成员,放在 [0,3] 偏移的位置,
char a; // 第二个成员,自身长为 1 #pragma pack (4), 取小值,也就是 1 ,所以这个成员按一字节对齐,放在偏移 [4] 的位置。
short b; // 第三个成员,自身长 2 #pragma pack (4) ,取 2 ,按 2 字节对齐,所以放在偏移 [6,7] 的位置。
char c; // 第四个,自身长为 1 ,放在 [8] 的位置。
};
//
可以看出,上面的位置完全没有变化,只是类之间改为按 2 字节对齐, 9 2 圆整的结果是 10
//
所以 sizeof(TestB) 10

最后看原贴:
现在去掉第一个成员变量为如下代码:
#pragma pack (4)
class TestC
{
public:
char a;// 第一个成员,放在 [0] 偏移的位置,
short b;// 第二个成员,自身长 2 #pragma pack (4) ,取 2 ,按 2 字节对齐,所以放在偏移 [2,3] 的位置。
char c;// 第三个,自身长为 1 ,放在 [4] 的位置。
};
//
整个类的大小是 5 字节,按照 min(sizeof(short),4) 字节对齐,也就是 2 字节对齐,结果是 6
//
所以 sizeof(TestC) 6

对於位域有如下规定 :

C99 规定 int unsigned int bool 可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。使用位域的主要目的是压缩存储,其大致规则为:
1)
如果相邻位域字段的类型相同,且其位宽之和小于类型的 sizeof 大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2)
如果相邻位域字段的类型相同,但其位宽之和大于类型的 sizeof 大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3)
如果相邻的位域字段的类型不同,则各编译器的具体实现有差异, VC6 采取不压缩方式, Dev-C++ 采取压缩方式;
4)
如果位域字段之间穿插着非位域字段,则不进行压缩;
5)
整个结构体的总大小为最宽基本类型成员大小的整数倍。

还是让我们来看看例子。
示例 1
struct BF1
{
char f1 : 3;
char f2 : 4;
char f3 : 5;
};
其内存布局为:
|_f1__|__f2__|_|____f3___|____|
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
0 3 7 8 1316
位域类型为 char ,第 1 个字节仅能容纳下 f1 f2 ,所以 f2 被压缩到第 1 个字节中,而 f3
能从下一个字节开始。因此 sizeof(BF1) 的结果为 2

示例 2
struct BF2
{
char f1 : 3;
short f2 : 4;
char f3 : 5;
};
由于相邻位域类型不同,在 VC6 中其 sizeof 6 ,在 Dev-C++ 中为 2

示例 3
struct BF3
{
char f1 : 3;
char f2;
char f3 : 5;
};
非位域字段穿插在其中,不会产生压缩,在 VC6 Dev-C++ 中得到的大小均为 3




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1331903

转自 :http://rabbitlzx.blogbus.com/logs/2006/03/2094407.html

1 、什么是 sizeof

首先看一下 sizeof msdn 上的定义:

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

看到 return 这个字眼,是不是想到了函数?错了, sizeof 不是一个函数,你见过给一个函数传参数,而不加括号的吗? sizeof 可以,所以 sizeof 不是函数。网上有人说 sizeof 是一元操作符,但是我并不这么认为,因为 sizeof 更像一个特殊的宏,它是在编译阶段求值的。举个例子:

cout<<sizeof(int)<<endl; // 32
位机上 int 长度为 4
cout<<sizeof(1==2)<<endl; // ==
操作符返回 bool 类型,相当于 cout<<sizeof(bool)<<endl;

在编译阶段已经被翻译为:

cout<<4<<endl;
cout<<1<<endl;

这里有个陷阱,看下面的程序:

int a = 0;
cout<<sizeof(a=3)<<endl;
cout<<a<<endl;

输出为什么是 4 0 而不是期望中的 4 3 ???就在于 sizeof 在编译阶段处理的特性。由于 sizeof 不能被编译成机器码,所以 sizeof 作用范围内,也就是 () 里面的内容也不能被编译,而是被替换成类型。 = 操作符返回左操作数的类型,所以 a=3 相当于 int ,而代码也被替换为:

int a = 0;
cout<<4<<endl;
cout<<a<<endl;

所以, sizeof 是不可能支持链式表达式的,这也是和一元操作符不一样的地方。

结论:不要把 sizeof 当成函数,也不要看作一元操作符,把他当成一个特殊的编译预处理。

2 sizeof 的用法

sizeof
有两种用法:

1 sizeof(object)
也就是对对象使用 sizeof ,也可以写成 sizeof object 的形式

2 sizeof(typename)
也就是对类型使用 sizeof ,注意这种情况下写成 sizeof typename 是非法的。下面举几个例子说明一下:


int i = 2;
cout<<sizeof(i)<<endl; // sizeof(object)
的用法,合理
cout<<sizeof i<<endl; // sizeof object
的用法,合理
cout<<sizeof 2<<endl; // 2
被解析成 int 类型的 object, sizeof object 的用法,合理
cout<<sizeof(2)<<endl; // 2
被解析成 int 类型的 object, sizeof(object) 的用法,合理
cout<<sizeof(int)<<endl;// sizeof(typename)
的用法,合理
cout<<sizeof int<<endl; //
错误!对于操作符,一定要加 ()

可以看出,加 () 是永远正确的选择。

结论:不论 sizeof 要对谁取值,最好都加上 ()


3 、数据类型的 sizeof

1 C++ 固有数据类型

32
C++ 中的基本数据类型,也就 char,short int(short),int,long int(long),float,double, long double
大小分别是: 1 2 4 4 4 8, 10

考虑下面的代码:

cout<<sizeof(unsigned int) == sizeof(int)<<endl; //
相等,输出 1

unsigned
影响的只是最高位 bit 的意义, 数据长度不会被改变的

结论: unsigned 不能影响 sizeof 的取值。

2 )自定义数据类型

typedef
可以用来定义 C++ 自定义类型。考虑下面的问题:

typedef short WORD;
typedef long DWORD;
cout<<(sizeof(short) == sizeof(WORD))<<endl; //
相等,输出 1
cout<<(sizeof(long) == sizeof(DWORD))<<endl; //
相等,输出 1

结论:自定义类型的 sizeof 取值等同于它的类型原形。

3 )函数类型

考虑下面的问题:

int f1(){return 0;};
double f2(){return 0.0;}
void f3(){}

cout<<sizeof(f1())<<endl; // f1()
返回值为 int ,因此被认为是 int
cout<<sizeof(f2())<<endl; // f2()
返回值为 double ,因此被认为是 double
cout<<sizeof(f3())<<endl; //
错误! 无法对 void 类型使用 sizeof
cout<<sizeof(f1)<<endl; //
错误!无法对函数指针使用 sizeof
cout<<sizeof*f2<<endl; // *f2
,和 f2() 等价,因为可以看作 object ,所以括号不是必要的。被认为是 double

结论:对函数使用 sizeof ,在编译阶段会被函数返回值的类型取代。

4
、指针问题

考虑下面问题:

cout<<sizeof(string*)<<endl; // 4
cout<<sizeof(int*)<<endl; // 4
cout<<sizof(char****)<<endl; // 4

可以看到, 不管是什么类型的指针, 大小都是 4 ,因为指针就是 32 位的物理地址。指针存放在 32 位物理地址中

结论:只要是指针,大小就是 4 。( 64 位机上要变成 8 也不一定)。

顺便唧唧歪歪几句, C++ 中的指针表示实际内存的地址。和 C 不一样的是, C++ 中取消了模式之分,也就是不再有 small,middle,big, 取而代之的是统一的 flat flat 模式采用 32 位实地址寻址,而不再是 c 中的 segment:offset 模式。举个例子,假如有一个指向地址 f000:8888 的指针,如果是 C 类型则是 8888(16 , 只存储位移,省略段 ) far 类型的 C 指针是 f0008888(32 位,高位保留段地址,地位保留位移 ),C++ 类型的指针是 f8888(32 位,相当于段地址 *16 + 位移,但寻址范围要更大 )

5
、数组问题

考虑下面问题:

char a[] = "abcdef";
int b[20] = {3, 4};
char c[2][3] = {"aa", "bb"};


cout<<sizeof(a)<<endl; // 7
cout<<sizeof(b)<<endl; // 80
cout<<sizeof(c)<<endl; // 6


数组 a 的大小在定义时未指定,编译时给它分配的空间是按照初始化的值确定的,也就是 7 c 是多维数组,占用的空间大小是各维数的乘积,也就是 6 。可以看出, 数组的大小就是他在编译时被分配的空间,也就是各维数的乘积 * 数组元素的大小。

结论:数组的大小是各维数的乘积 * 数组元素的大小。

这里有一个陷阱:

int *d = new int[10];

cout<<sizeof(d)<<endl; // 4

d
是我们常说的动态数组,但是他实质上还是一个指针,所以 sizeof(d) 的值是 4

再考虑下面的问题:

double* (*a)[3][6];

cout<<sizeof(a)<<endl; // 4
cout<<sizeof(*a)<<endl; // 72
cout<<sizeof(**a)<<endl; // 24
cout<<sizeof(***a)<<endl; // 4
cout<<sizeof(****a)<<endl; // 8

a
是一个很奇怪的定义,他表示一个指向 double*[3][6] 类型数组的指针。既然是指针,所以 sizeof(a) 就是 4

既然 a 是执行 double*[3][6] 类型的指针, *a 就表示一个 double*[3][6] 的多维数组类型,因此 sizeof(*a)=3*6*sizeof(double*)=72 。同样的, **a 表示一个 double*[6] 类型的数组,所以 sizeof(**a)=6*sizeof(double*)=24 ***a 就表示其中的一个元素,也就是 double* 了,所以 sizeof(***a)=4 。至于 ****a ,就是一个 double 了,所以 sizeof(****a)=sizeof(double)=8


6
、向函数传递数组的问题

考虑下面的问题:
#include <iostream>
using namespace std;

int Sum(int i[])
{
int sumofi = 0;
for (int j = 0; j < sizeof(i)/sizeof(int); j++) //
实际上, sizeof(i) = 4
{
sumofi += i[j];
}
return sumofi;
}

int main()
{
int allAges[6] = {21, 22, 22, 19, 34, 12};
cout<<Sum(allAges)<<endl;
system("pause");
return 0;
}

Sum
的本意是用 sizeof 得到数组的大小,然后求和。但是实际上,传入自函数 Sum 的,只是一个 int 类型的指针,所以 sizeof(i)=4 ,而不是 24 ,所以会产生错误的结果。解决这个问题的方法使是用指针或者引用。

使用指针的情况:
int Sum(int (*i)[6])
{
int sumofi = 0;
for (int j = 0; j < sizeof(*i)/sizeof(int); j++) //sizeof(*i) = 24
{
sumofi += (*i)[j];
}
return sumofi;
}

int main()
{
int allAges[] = {21, 22, 22, 19, 34, 12};
cout<<Sum(&allAges)<<endl;
system("pause");
return 0;
}
在这个 Sum 里, i 是一个指向 i[6] 类型的指针,注意,这里不能用 int Sum(int (*i)[]) 声明函数,而是 必须指明要传入的数组的大小, 不然 sizeof(*i) 无法计算。但是在这种情况下,再通过 sizeof 来计算数组大小已经没有意义了,因为此时大小是指定为 6 的。
使用引用的情况和指针相似:

int Sum(int (&i)[6])
{
int sumofi = 0;
for (int j = 0; j < sizeof(i)/sizeof(int); j++)
{
sumofi += i[j];
}
return sumofi;
}

int main()
{
int allAges[] = {21, 22, 22, 19, 34, 12};
cout<<Sum(allAges)<<endl;
system("pause");
return 0;
}
这种情况下 sizeof 的计算同样无意义,所以用数组做参数,而且需要遍历的时候,函数应该有一个参数来说明数组的大小,而数组的大小在数组定义的作用域内通过 sizeof 求值。因此上面的函数正确形式应该是:
#include <iostream>
using namespace std;

int Sum(int *i, unsigned int n)
{
int sumofi = 0;
for (int j = 0; j < n; j++)
{
sumofi += i[j];
}
return sumofi;
}

int main()
{
int allAges[] = {21, 22, 22, 19, 34, 12};
cout<<Sum(i, sizeof(allAges)/sizeof(int))<<endl;
system("pause");
return 0;
}

7
、字符串的 sizeof strlen

考虑下面的问题:

char a[] = "abcdef";
char b[20] = "abcdef";
string s = "abcdef";

cout<<strlen(a)<<endl; // 6
,字符串长度
cout<<sizeof(a)<<endl; // 7
,字符串容量
cout<<strlen(b)<<endl; // 6
,字符串长度
cout<<strlen(b)<<endl; // 20
,字符串容量
cout<<sizeof(s)<<endl; // 12,
这里不代表字符串的长度,而是 string 类的大小
cout<<strlen(s)<<endl; //
错误! s 不是一个字符指针。

a[1] = '';
cout<<strlen(a)<<endl; // 1
cout<<sizeof(a)<<endl; // 7
sizeof 是恒定的 因空间已开辟


strlen
是寻找从指定地址开始,到出现的第一个 0 之间的字符个数,他是在运行阶段执行的,而 sizeof 是得到数据的大小,在这里是得到字符串的容量。 所以对同一个对象而言, sizeof 的值是恒定的。 string C++ 类型的字符串,他是一个类,所以 sizeof(s) 表示的并不是字符串的长度,而是类 string 的大小。 strlen(s) 根本就是错误的,因为 strlen 的参数是一个字符指针,如果想用 strlen 得到 s 字符串的长度,应该使用 sizeof(s.c_str()) ,因为 string 的成员函数 c_str() 返回的是字符串的首地址。实际上, string 类提供了自己的成员函数来得到字符串的容量和长度,分别是 Capacity() Length() string 封装了常用了字符串操作,所以在 C++ 开发过程中,最好使用 string 代替 C 类型的字符串。


8
、从 union sizeof 问题看 cpu 的对界

考虑下面问题:(默认对齐方式)

union u
{
double a;
int b;
};

union u2
{
char a[13];
int b;
};

union u3
{
char a[13];
char b;
};

cout<<sizeof(u)<<endl; // 8
cout<<sizeof(u2)<<endl; // 16
cout<<sizeof(u3)<<endl; // 13

都知道 union 的大小取决于它所有的成员中,占用空间最大的一个成员的大小。所以对于 u 来说,大小就是最大的 double 类型成员 a 了,所以 sizeof(u)=sizeof(double)=8 。但是对于 u2 u3 ,最大的空间都是 char[13] 类型的数组,为什么 u3 的大小是 13 ,而 u2 16 呢?关键在于 u2 中的成员 int b 。由于 int 类型成员的存在,使 u2 的对齐方式变成 4 ,也就是说, u2 的大小必须在 4 的对界上 ( 4 的倍数 ) ,所以占用的空间变成了 16 (最接近 13 的对界)。

结论:复合数据类型,如 union struct class 的对齐方式为成员中对齐方式 最大的成员 的对齐方式。

顺便提一下 CPU 对界问题, 32 C++ 采用 8 位对界来提高运行速度,所以编译器会尽量把数据放在它的对界上以提高内存命中率。对界是可以更改的,使用 #pragma pack(x) 宏可以改变编译器的对界方式, 默认是 8 C++ 固有类型的对界取 编译器对界方式与自身大小中较小的一个 。例如,指定编译器按 2 对界, int 类型的大小是 4 ,则 int 的对界为 2 4 中较小的 2 。在默认的对界方式下,因为几乎所有的数据类型都不大于默认的对界方式 8 (除了 long double ),所以所有的固有类型的对界方式可以认为就是类型自身的大小。更改一下上面的程序:

#pragma pack(2)
union u2
{
char a[13];
int b;
};

union u3
{
char a[13];
char b;
};
#pragma pack(8)

cout<<sizeof(u2)<<endl; // 14
cout<<sizeof(u3)<<endl; // 13

由于手动更改对界方式为 2 ,所以 int 的对界也变成了 2 u2 的对界取成员中最大的对界 ,也是 2 了,所以此时 sizeof(u2)=14

结论: C++ 固有类型的对界取编译器对界方式与自身大小中较小的一个。

9 struct sizeof 问题

因为对齐问题使结构体的 sizeof 变得比较复杂,

看下面的例子: ( 默认对齐方式下 )

struct s1{

char a;

double b;

int c;

char d;

};

struct s2{

char a;

char b;

int c;

double d;

};

cout<<sizeof(s1)<<endl; // 24

cout<<sizeof(s2)<<endl; // 16

同样是两个 char 类型,一个 int 类型,一个 double 类型,但是

因为对界问题,导致他们的大小不同。计算结构体大小可以采用

元素摆放法,我举例子说明一下:首先, CPU 判断结构体的对界,

根据上一节的结论, s1 s2 的对界都取最大的元素类型,也就是

double 类型的对界 8 。然后开始摆放每个元素。

对于 s1 ,首先把 a 放到 8 的对界,假定是 0 ,此时下一个空闲的地址

1 ,但是下一个元素 b double 类型,要放到 8 的对界上,离 1

最接近的地址是 8 了,所以 b 被放在了 8 ,此时下一个空闲地址变成

16 ,下一个元素 c 的对界是 4 16 可以满足,所以 c 放在了 16

此时下一个空闲地址变成了 20 ,下一个元素 d 需要对界 1 ,也正好

落在对界上,所以 d 放在了 20 ,结构体在地址 21 处结束。由于 s1

大小需要是 8 的倍数 ,所以 21-23 的空间被保留, s1 的大小变成

24

对于 s2 ,首先把 a 放到 8 的对界,假定是 0 ,此时下一个空闲地址

1 ,下一个元素的对界也是 1 ,所以 b 摆放在 1 ,下一个空闲地址

变成了 2 ;下一个元素 c 的对界是 4 ,所以取离 2 最近的地址 4 摆放 c( 4 个字节作一个单位,第一个单位已被占用 )

下一个空闲地址变成了 8 ,下一个元素 d 的对界是 8 ,所以 d 摆放在 8

所有元素摆放完毕,结构体在 15 处结束,占用总空间为 16 ,正好

8 的倍数。

这里有个陷阱,对于结构体中的结构体成员,不要认为它的

对齐方式就是他的大小,看下面的例子:

struct s1{

char a[8];

};

struct s2{

double d;

};

struct s3{

s1 s;

char a;

};

struct s4{

s2 s;

char a;

};

cout<<sizeof(s1)<<endl; // 8

cout<<sizeof(s2)<<endl; // 8

cout<<sizeof(s3)<<endl; // 9

cout<<sizeof(s4)<<endl; // 16;

s1 s2 大小虽然都是 8 ,但是 s1 的对齐方式是 1 s2 8 double ),

所以在 s3 s4 中才有这样的差异。所以,在自己定义结构体的时候,如果空间紧张的话,最好考虑

对齐因素来排列结构体里的元素。

10 、不要让 double 干扰你的位域

在结构体和类中,可以使用位域来规定某个成员所能占用的空间,

所以 使用位域能在一定程度上节省结构体占用的空间

不过考虑下面的代码:

struct s1{

int i: 8;

int j: 4;

double b;

int a:3;

};

struct s2{

int i;

int j;

double b;

int a;

};

struct s3{

int i;

int j;

int a;

double b;

};

struct s4{

int i: 8;

int j: 4;

int a:3;

double b;

};

cout<<sizeof(s1)<<endl; // 24

cout<<sizeof(s2)<<endl; // 24

cout<<sizeof(s3)<<endl; // 24

cout<<sizeof(s4)<<endl; // 16

可以看到,有 double 存在会干涉到位域( sizeof 的算法参考上

一节),所以使用位域的的时候,最好把 float 类型和 double

类型放在程序的 开始或者最后

------------------------------------------------------------

------------------------------------------------------------

sizeof 在求结构大小时的使用及 sizeof 主要用法
Tag:
program

本文主要包括二个部分,第一部分重点介绍在 VC 中,怎么样采用 sizeof 来求结构的大小,以及容易出现的问题,并给出解决问题的方法,第二部分总结出 VC sizeof 的主要用法。

1 sizeof 应用在结构上的情况

请看下面的结构:

struct MyStruct

{

double dda1;

char dda;

int type

};


对结构 MyStruct 采用 sizeof 会出现什么结果呢? sizeof(MyStruct) 为多少呢?也许你会这样求:

sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13

但是当在 VC 中测试上面结构的大小时,你会发现 sizeof(MyStruct) 16 。你知道为什么在 VC 中会得出这样一个结果吗?

其实,这是 VC 对变量存储的一个特殊处理。 为了提高 CPU 的存储速度, VC 对一些变量的起始地址做了 对齐 处理。 在默认情况下, VC 规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式 (vc6.0,32 位系统 )

类型
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)

Char
偏移量必须为 sizeof(char) 1 的倍数

int
偏移量必须为 sizeof(int) 4 的倍数

float
偏移量必须为 sizeof(float) 4 的倍数

double
偏移量必须为 sizeof(double) 8 的倍数

Short
偏移量必须为 sizeof(short) 2 的倍数




各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节 VC 会自动填充。同时 VC 为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节

下面用前面的例子来说明 VC 到底怎么样来存放结构的。

struct MyStruct

{

double dda1;

char dda;

int type

}


为上面的结构分配空间的时候, VC 根据成员变量出现的顺序和对齐方式,先为第一个成员 dda1 分配空间,其起始地址跟结构的起始地址相同(刚好偏移量 0 刚好为 sizeof(double) 的倍数),该成员变量占用 sizeof(double)=8 个字节;接下来为第二个成员 dda 分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为 8 ,是 sizeof(char) 的倍数,所以把 dda 存放在偏移量为 8 的地方满足对齐方式,该成员变量占用 sizeof(char)=1 个字节;接下来为第三个成员 type 分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为 9 ,不是 sizeof(int)=4 的倍数,为了满足对齐方式对偏移量的约束问题, VC 自动填充 3 个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为 12 ,刚好是 sizeof(int)=4 的倍数,所以把 type 存放在偏移量为 12 的地方,该成员变量占用 sizeof(int)=4 个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为: 8+1+3+4=16 ,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数 sizeof(double)=8 )的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为: sizeof(MyStruct)=8+1+3+4=16 ,其中有 3 个字节是 VC 自动填充的,没有放任何有意义的东西。

下面再举个例子,交换一下上面的 MyStruct 的成员变量的位置,使它变成下面的情况:

struct MyStruct

{

char dda;

double dda1;

int type

}


这个结构占用的空间为多大呢?在 VC6.0 环境下,可以得到 sizeof(MyStruc) 24 。结合上面提到的分配空间的一些原则,分析下 VC 怎么样为上面的结构分配空间的。(简单说明)

struct MyStruct

{

char dda;//
偏移量为 0 ,满足对齐方式, dda 占用

分享到:
评论
wapysun
  • 浏览: 4881624 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最新评论

sizeof 用法


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论