文档库 最新最全的文档下载
当前位置:文档库 › 数据对齐问题

数据对齐问题

数据对齐问题
数据对齐问题

为什么会产生数据对齐问题

8位CPU 当然不会产生数据对齐问题,当CPU发展到16,32位时,因为CPU的一次内存访问就能取回4个byte(且用32位举例,这个数据理所当然的缓存在相应的32位寄存器中)——里面可能存储了4个1byte的数据,也可能存储了2个2byte的数据……,所以CPU 在逻辑上将内存单元寻址地址边界设置为4的倍数(如:0,4,8,12……),这是数据对齐产生的必要条件之一;另一个原因是程序中使用的数据类型并非都是4的倍数,如:char (1byte),short(2byte),int(4byte)等等。让我们考虑一下一个2byte的的变量在内存单元中排布吧:如果这个变量地址为0或1或2,那么CPU一次内存访问就能够取得你的变量;但如果是3的话,很不幸,CPU还得访问一次内存以取得全部数据。

对几组sizeof信息的分析

对于很多C++新手而言,对象或变量的sizeof信息总是让人捉摸不透,以下程序列举了几个典型的sizeof信息,希望能解答大家在使用sizeof时的疑问。

在列举这几个例子前需要说明以下几点:

1、在Win32平台上,指针长度都是4字节,char*、int*、double*如此,vbptr(virtual base tabl

e pointer)、vfptr(virtual function table pointer)也是如此;

2、对于结构体(或类),编译器会自动进行成员变量的对齐,以提高运算效率。自然对齐(natural a lignment)也称默认对齐方式是按结构体的成员中size最大的成员对齐的,强制指定大于自然对齐大小的对齐方式是不起作用的。

3、不推荐强制对齐,大量使用强制对齐会严重影响处理器的处理效率。

范例1:(一个简单的C语言的例子)

void f(int arr[])

{

cout << "sizeof(arr) = " << sizeof(arr) << endl; //当被作为参数进行传递时,数组失去了其大小信息

}

void main()

{

char szBuf[] = "abc";

cout << "sizeof(szBuf) = " << sizeof(szBuf) << endl; //输出数组占用空间大小

char* pszBuf = szBuf;

cout << "sizeof(pszBuf) = " << sizeof(pszBuf) << endl; //输出的是指针的大小

int iarr[3]; iarr;

cout << "sizeof(iarr) = " << sizeof(iarr) << endl; //输出数组占用空间大小

f(iarr);

int* piarr = iarr;

cout << "sizeof(piarr) = " << sizeof(piarr) << endl; //输出指针的大小

}

范例2:(一个涉及alignment的例子)

struct DATA1

{

char c1; //偏移量0,累积size = 1

char c2; //偏移量1,累积size = 1 + 1 = 2

short si; //偏移量2,累积size = 2 + 2

};

struct DATA2

{

char c1; //偏移量0,累积size = 1

short si; //偏移量1 + (1),累积size = 1 + (1) + 2 = 4

char c2; //偏移量4,累积size = 4 + 1 = 5,但按最大长度sizeof(short) = 2对齐,故最后取6

};

struct DATA3

{

char c1; //偏移量0,累积size = 1

double d; //偏移量1 + (7),累积size = 1 + (7) + 8 = 16

char c2; //偏移量16,累积size = 16 + 1 = 17,但按最大长度sizeof(double) = 8对齐,故最后取24

};

#pragma pack(push,1) //强制1字节对齐

struct DATA4

{

char c1; //偏移量0,累积size = 1

double d; //偏移量1,累积size = 1 + 8 = 9

char c2; //偏移量9,累积size = 9 + 1 = 10

};

#pragma pack(pop) //恢复默认对齐方式

struct DATA5

{

char c1;

double d;

char c2;

};

void main()

{

cout << "sizeof(DATA1) = " << sizeof(DATA1) << endl;

cout << "sizeof(DATA2) = " << sizeof(DATA2) << endl;

cout << "sizeof(DATA3) = " << sizeof(DATA3) << endl;

cout << "sizeof(DATA4) = " << sizeof(DATA4) << endl;

cout << "sizeof(DATA5) = " << sizeof(DATA5) << endl;

}

范例3:(C++语言特征对sizeof的影响)

class CA

{

};

class CB : public CA

{

public:

void func() {}

};

class CC : virtual public CA

{

};

class CD

{

int k; //私有成员

public:

CD() {k = -1;}

void printk() { cout << "k = " << k << endl; } };

class CE : public CD

{

};

class CF

{

virtual void func() {}

};

void main()

{

cout << "sizeof(CA) = " << sizeof(CA) << endl; //为了区分不包含任何成员的类的不同的元素,编译器会自动为类添加一个匿名元素

cout << "sizeof(CB) = " << sizeof(CB) << endl; //与上面类似,编译器也为CB添加了一个匿名元素

cout << "sizeof(CC) = " << sizeof(CC) << endl; //虚拟继承中vbptr(virtual base table pointe r)占用4个字节

cout << "sizeof(CD) = " << sizeof(CD) << endl;

cout << "sizeof(CE) = " << sizeof(CE) << endl; //访问权限控制是在编译期间由编译器控制的,所以虽然不能访问CD类的成员k,这里仍然占用了sizeof(int)大小的空间

//下面的代码进一步说明上述观点,由于在复杂的类层次结构中,当涉及到虚函数或者虚拟继承等时,有些信息是运行期动态生成的,故请勿效仿以下方法对对象进行修改

CE e;

e.printk();

memset(&e, 0, sizeof(CE));

e.printk(); //从这里可以看出,上面的memset操作修改了CD类的私有成员k

cout << "sizeof(CF) = " << sizeof(CF) << endl; //虚函数表指针占有4个字节

}

在论坛上问如下代码结果为什么是24?

union DATE

{

char a;

int i[5];

double b;

};

DATE max;

cout<< sizeof(max) << endl;

这个问题很好回答,并且我把这个问题归结于基本概念题(就是入门书必须介绍的)。我想一般来说,做过内存管理的,对这个语言特性肯定不会陌生。

摘几句The C Programming Language里面讲述这个问题的原话,以说明读书还是必要的:

①联合就是一个结构,②它的所有成员相对于基地址的偏移量都为0,③此结构空间要大到足够容纳最“宽”的成员,④并且,其对齐方式要适合于联合中所有类型的成员。

怕有的兄弟还不明白,特附图一个帮助理解:

该结构要放得下int i[5]必须要至少占4×5=20个字节。如果没有double的话20个字节够用了,此时按4字节对齐。但是加入了double就必须考虑double的对齐方式,double是按照8字节对齐的,所以必须添加4个字节使其满足8×3=24,也就是必须也是8的倍数,这样一来就出来了24这个数字。综上所述,最终联合体的最小的size也要是所包含的所有类型的基本长度的最小公倍数才行。(这里的字节数均指winnt下的值,平台、编译器不同值也有可能不同。)

联合在存储分配的时候用的机会最多,因为很少有像存储分配这样需要给多种不同类型的变量分配空间而又打算尽可能的节约内存的,这很适合联合的特性。上述对齐的方式有个很有趣的用法也就常在存储分配里面使用。(下面依旧用The C Programming Language中的例子作答)

typedef long Align;

union header {

struct {

union header *ptr;

unsigned size;

} s;

Align x;

}

这里的Align有什么用?作用只有一个,就是强迫分配的结构体按long的长度对齐。爱书吧,它是知识的源泉!~~

简要记录sizeof和内存对齐

本来,一般是不自己计算sizeof的,知道内存对齐会对sizeof有影响,所以从来不手算,而是代码里写上sizeof。今天又看到https://www.wendangku.net/doc/bc15853041.html,/smileonce/archive/2005/08/08/1065 8.html,翻来了https://www.wendangku.net/doc/bc15853041.html,/billdavid/archive/2004/06/23/509.html,自己想想还是也记录一下,万一以后自己真的也要计算sizeof,忘了,还能有个提示,也给不是很明白的朋友一个参考。

struct sample1

{

char a; /// sizeof(char) = 1

double b; /// sizeof(double) = 8

};

///default( 缺省#pragam pack(8) ——VC6和VC71,其它编译器,个人未知) ///1+8 = 9 —> 16( 8 < 9 < 16 )

#pragma pack( 4 )

///1+8 = 9 —> 12( 8 < 9 < 12 )

#pragma pack( 2 )

///1+8 = 9 —> 10( 8 < 9 < 10 )

#pragma pack( 1 )

///1+8 = 9 —> 9

#pragma pack( 16 )

///1+8 = 9 —> 16( 16—>8 ---- 8 < 9 < 16 )

struct sample2

{

char a; ///1

int b; ///4

};

#pragma pack( 8 )

/// 1 + 4 = 5 —> 8( 8 —> 4 )

#pragma pack( 16 )

/// 1 + 4 = 5 —> 8( 16 —> 4 )

说明:#pragma pack告诉编译器进行内存边界对齐,一般都是采用编译器的设置对整个项目采用同一对齐方案,而且通常为缺省8字节对齐。

/////////////////////////////////以下内容于2005-12-10 添加/////////////////////////////////

今天又看到以前测试的一段代码,突然不明白了起来,又稍写了几个测试。

struct sample3

{

char a; ///1

int b; ///4

char c; ///1

};

///default ///12

#pragma pack( 4 ) ///12

#pragma pack( 2 ) ///08

#pragma pack( 1 ) ///06

#pragma pack( 16 ) ///12

原来,其实编译器,根据对齐指示的对齐字节和最大成员的字节,对每个成员进行了对齐:

编译器会取对齐指示和最大成员字节中较小的一个用于补齐其它成员。那么,上面的sample1/ 2/3也就都在情理之中了。为了证实这点,我们还再看一个例子:

struct sample4

{

char a; ///1

int b; ///4

double c; ///8

char d; ///1

};

///default: ///8+8+8+8 = 32

#pragma pack( 4 ) ///4+4+8+4 = 20

#pragma pack( 2 ) ///2+4+8+2 = 16

#pragma pack( 1 ) ///1+4+8+1 = 14

#pragma pack( 16 ) ///8+8+8+8 = 32

而实际上,编译器给出的值是:24、20、16、14、24

那么说明我错了。注意一下,我发现char a,int b加起来也才5<8,难到编译器进行了联合对齐?struct sample5

{

char a; ///1

double c; ///8

int b; ///4

char d; ///1

};

编译器给出结果:24、20、16、14、24

这用联合对齐的解释正好符合,我又试验了不同的数据,发现这个结论并不太准确确。于是,我输出了每一个对象成员地址进行分析。由于试验数据量很大,这里就不列出了。

最后得到了以下结论:

1. 成员的对齐是按声明顺序进行的;

2. 对齐值由编译指示和最大成员两者较小的值决定;

3. 未对齐到对齐值的成员一起形成块对齐(联合对齐);

4. 上一个(下一个)对齐采用自己较大则不变,自己较小则填充自己对齐到上一个(下一个)大小;

5. 每成员对齐:如果前面已对齐到对齐值,下一个对齐自己。如果前面未对齐到对齐值,如果加上下一个成员不大于对齐值,下一个对齐自己,否则填充自己块对齐到对齐值。

6. 最后还未对齐到对齐值的,填充空间块对齐到对齐值。

从这些结论,可以得到:

1. 以上的对齐原则其实是尽量整齐排列、尽量节省内存。

2. 声明成员应该尽量避免不同类型错杂开来,最好采用从小到大或者从大到小的顺序(错开后,会因为上对齐和下对齐而增加填充开销)。

3. 编译器缺省采用8字节对齐主要是因为最大基本类型为8自己(以前自己不明白,在论坛提过问,后来,以为是SSE指令的原因)。

4. 手算sizeof是没有必要的,负责的(可以先对齐出对齐块,用块数乘对齐值)。

sizeof进行结构体大小的判断

sizeof进行结构体大小的判断 typedef struct { int a; char b; }A_t; typedef struct { int a; char b; char c; }B_t; typedef struct { char a; int b; char c; }C_t; void main() { char*a=0; cout<

2. 语法: sizeof有三种语法形式,如下: 1) sizeof( object ); // sizeof( 对象); 2) sizeof( type_name ); // sizeof( 类型); 3) sizeof object; // sizeof 对象; 5. 指针变量的sizeof 既然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中,一 个指针变量的返回值必定是4(以字节为单位),可以预计,在将来的64位系统中指针变量的sizeof结果为8。 char* pc = "abc"; int* pi; string* ps; char** ppc = &pc; void (*pf)();// 函数指针 sizeof( pc ); // 结果为4 sizeof( pi ); // 结果为4 sizeof( ps ); // 结果为4 sizeof( ppc ); // 结果为4 sizeof( pf );// 结果为4 指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内存大小相等,所以MFC消息处理函数使用两个参数WPARAM、LPARAM 就能传递各种复杂的消息结构(使用指向结构体的指针)。 6. 数组的sizeof 数组的sizeof值等于数组所占用的内存字节数,如: char a1[] = "abc"; int a2[3];

内存对齐方式

对齐方式 为什么会有内存对齐? 在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间;各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。在缺省情况下,C编译器为每一个变量或数据单元按其自然对界条件分配空间。 字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。 一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。 某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。 影响结构体的sizeof的因素: 1)不同的系统(如32位或16位系统):不同的系统下int等类型的长度是变化的,如对于16位系统,int的长度(字节)为2,而在32位系统下,int的长度为4;因此如果结构体中有int等类型的成员,在不同的系统中得到的sizeof值是不相同的。 2)编译器设置中的对齐方式:对齐方式的作用常常会让我们对结构体的sizeof 值感到惊讶,编译器默认都是8字节对齐。 对齐: 为了能使CPU对变量进行高效快速的访问,变量的起始地址应该具有某些特性,即所谓的“对齐”。例如对于4字节的int类型变量,其起始地址应位于4字节边界上,即起始地址能够被4整除。变量的对齐规则如下(32位系统)

C 语言中 地址对齐与数据对齐

------------------------------Editor: JaceLin-----------------Date: 2014.2.7--------------------------- C语言中的地址&数据对齐 NOTE: 在单片机开发中,不论是什么样的单片机,打开官方头文件都会发现,里面全是各种各样的结构体(struct)与宏定义(define),但不论定义的字母多么长多么难懂,它们的最终映像都是一个16进制的地址。对于一个单片机初学者来说,看到这些定义往往会很头痛,因为平时基本都是用别人的头文件,很少去写自己的单片机头文件。 前几天一直在写一个freescal K60单片机DMA程序,DMA就是‘直接对寄存器存取’,顾名思义,这个程序要涉及寄存器的操作(其实所有的单片机程序都是操作寄存器,只是定义了宏不直观而已)!DMA对于我来说第一次接触,中间就接触到了许多关于前面所说的官方给的struct与define,但是我感觉他们写的都很啰嗦过于繁琐,于是为了简化程序,我不得不弄清楚这些定义到底是什么意思。我专门去网上找了很多关于这方面的资料,最后我得出结论,其实就是两个方面内容:地址对齐与数据对齐! 下面就让我来解读这些难懂的struct & define. 一、数据对齐(以下内容都以32bit x86/arm平台为例) 在没有#progma pack(n)参数的情况下: 例1: struct A{ char a; char b; char c; }; Sixeof(struct A) =多少? 分析:一个char 长度为1个字节,而内存单元为4个字节,以上struct A 占用内存如下图:

结构体对齐

关于 C 语言中的结构体对齐 (1)什么是字节对齐 一个变量占用 n 个字节,则该变量的起始地址必须能够被n 整除,即: 存放起始地址 % n = 0 ,对于结构体而言,这个 n 取其成员种的数据类型占空间的值最大的那个。 (2)为什么要字节对齐 内存空间是按照字节来划分的,从理论上说对内存空间的访问可以从任何地址开始,但是在实际上不同架构的 CPU 为了提高访问内存的速度,就规定了对于某些类型的数据只能从特定的起始位置开始访问。这样就决定了各种数据类型只能按照相应的规则在内存空间中存放,而不能一个接一个的顺序排列。 举个例子,比如有些平台访问内存地址都从偶数地址开始,对于一个 int 型( 假设 32 位系统 ),如果从偶数地址开始的地方存放,这样一个读周期就可以读出这个 int 数据,但是如果从奇数地址开始的地址存放,就需要两个读周期,并对两次读出的结果的高低字节进行拼凑才能得到这个 int 数据,这样明显降低了读取的效率。 (3)如何进行字节对齐 每个成员按其类型的对齐参数 (通常是这个类型的大小 )和指定对齐参数 ( 不指定则取默认值 ) 中较小的一个对齐,并且结构的长度必须为所用过的所有对齐参数的整数倍 ,不够就补空字节。 这个规则有点苦涩,可以把这个规则分解一下,前半句的意思先获得对齐值后与指定对齐值进行比较 ,其中对齐值获得方式如下:

1. 数据类型的自身对齐值为:对于 char 型数据,其自身对齐值为 1 ,对于 short 型为 2 ,对于 int, long, float 类型,其自身对齐值为 4 ,对于 double 类型其自身对齐值为 8 ,单位为字节。 2. 结构体自身对齐值:其成员中自身对齐值最大的那个值。 其中指定对齐值获得方式如下: #pragma pack (value) 时的指定对齐值 value 。 未指定则取默认值。 后半句的意思是主要是针对于结构体的长度而言,因为针对数据类型的成员,它仅有一个对齐参数,其本身的长度、于这个对齐参数,即 1 倍。对于结构体而言,它可能使用了多种数据类型,那么这句话翻译成对齐规则:每个成员的起始地址 % 自身对齐值 = 0 ,如果不等于0 则先补空字节直至这个表达式成立。 换句话说,对于结构体而言,结构体在在内存的存放顺序用如下规则即可映射出来: ( 一)每个成员的起始地址 % 每个成员的自身对齐值 = 0 ,如果不等于 0 则先补空字节直至这个表达式成立; ( 二 ) 结构体的长度必须为结构体的自身对齐值的整数倍, 不够就补空字节。 举个例子: #pragmapack(8) structA{ chara; longb; }; structB{

内存字节对齐

1.内存字节对齐和小端模式: /* 本程序是关于:编译器内存的字节对齐方式和存储时的小端对齐模式(win7 32bit) #pragma pack(n) 默认为8字节对齐,(即n=8)其中n的取值为1,2,4,8,16,32等 内存字节对齐大小和方式: 1)结构体内变量对齐: 每个变量的对齐字节数大小argAlignsize=min(#pragma pack(n),sizeof(变量)); 方式:结构体的第一个变量的初始偏移地址为0,其它变量的偏移地址(当前变量的起始地址)必须是argAlignsize的整数倍,不够整数倍的补空,不添加任何数据 2)结构体对齐: 结构体的对齐字节数大小strAlignsize=min(#pragma pack(n),sizeof(所有变量中最大字节的变量)) 方式: A.对于单独的结构体来说,结构体本身按照strAlignsize大小来对齐 B.结构体B在结构体A中时,结构体B的起始地址是结构体B的 strAlignsize大小的整数倍 小端对齐模式: 指针指着一个存储空间,存储空间地址由低到高的存储内容为:0x78,0x67,0x33,0x45 若指针为char,则获取的数据为0x78 若指针为short,则获取的数据为0x6778 若指针为long,则获取的数据为0x45336778 */ #include using namespace std; /*更改C编译器内存的缺省字节对齐方式,由默认的n=4字节,变为n字节对齐,其中n的取值为1,2,4,8,16,32等*/ #pragma pack(2) struct A { unsigned char a; unsigned short b; }; struct B { unsigned char c; unsigned int d;

寄存器sse2指令集

sse2指令集 1移动指令: 1. Movaps movaps XMM,XMM/m128 movaps XMM/128,XMM 把源存储器内容值送入目的寄存器,当有m128时,必须对齐内存16字节,也就是内存地址低4位为0. 2. Movups movups XMM,XMM/m128 movaps XMM/128,XMM 把源存储器内容值送入目的寄存器,但不必对齐内存16字节 3. Movlps movlps XMM,m64 把源存储器64位内容送入目的寄存器低64位,高64位不变,内存变量不必对齐内存16字节4. Movhps movhps XMM,m64 把源存储器64位内容送入目的寄存器高64位,低64位不变,内存变量不必对齐内存16字节. 5. Movhlps movhlps XMM,XMM 把源寄存器高64位送入目的寄存器低64位,高64位不变. 6. Movlhps movlhps XMM,XMM 把源寄存器低64位送入目的寄存器高64位,低64位不变. 7. movss movss XMM,m32/XMM 原操作数为m32时:dest[31-00] <== m32 dest[127-32] <== 0 原操作数为XMM时: dest[31-00] <== src[31-00] dest[127-32]不变 8. movmskpd movmskpd r32,XMM 取64位操作数符号位 r32[0] <== XMM[63] r32[1] <== XMM[127] r32[31-2] <== 0

9. movmskps movmskps r32,XMM 取32位操作数符号位 r32[0] <== XMM[31] r32[1] <== XMM[63] r32[2] <== XMM[95] r32[3] <== XMM[127] r32[31-4] <== 0 10. pmovmskb pmovmskb r32,XMM 取16位操作数符号位具体操作同前 r[0] <== XMM[7] r[1] <== XMM[15] r[2] <== XMM[23] r[3] <== XMM[31] r[4] <== XMM[39] r[5] <== XMM[47] r[6] <== XMM[55] r[7] <== XMM[63] r[8] <== XMM[71] r[9] <== XMM[79] r[10] <== XMM[87] r[11] <== XMM[95] r[12] <== XMM[103] r[13] <== XMM[111] r[14] <== XMM[119] r[15] <== XMM[127] r[31-16] <== 0 11. movntps movntps m128,XMM m128 <== XMM 直接把XMM中的值送入m128,不经过cache,必须对齐16字节. 12. Movntpd movntpd m128,XMM m128 <== XMM 直接把XMM中的值送入m128,不经过cache,必须对齐16字节. 13. Movnti movnti m32,r32 m32 <== r32 把32寄存器的值送入m32,不经过cache. 14. Movapd movapd XMM,XMM/m128 movapd XMM/m128,XMM 把源存储器内容值送入目的寄存器,当有m128时,必须对齐内存16字节 15. Movupd movupd XMM,XMM/m128 movapd XMM/m128,XMM 把源存储器内容值送入目的寄存器,但不必对齐内存16字节. 我感觉这两条指令同movaps 和movups 指令一样,不过又不确定. 16. Movlpd movlpd XMM,m64 movlpd m64,XMM 把源存储器64位内容送入目的寄存器低64位,高64位不变,内存变量不必对齐内存16字节

c++中关于结构体长度的计算问题

[C++]字节对齐与结构体大小 [C++] 2010-09-24 21:40:26 阅读172 评论0 字号:大中小订阅 说明: 结构体的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。这些问题在平时编程的时候也确实不怎么用到,但在一些笔试面试题目中出是常常出现,对sizeof我们将在另一篇文章中总结,这篇文章我们只总结结构体的sizeof,报着不到黄河心不死的决心,终于完成了总结,也算是小有收获,拿出来于大家分享,如果有什么错误或者没有理解透的地方还望能得到提点,也不至于误导他人。 一、解释 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如

有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int 型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。 二、准则 其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则: 1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节; 3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。 三、基本概念

内存对齐

C语言内存对齐 分类:C/C++2012-04-05 20:54 1070人阅读评论(1) 收藏举报语言c编译器平台oo 首先由一个程序引入话题: 1//环境:vc6 + windows sp2 2//程序1 3 #include 4 5using namespace std; 6 7struct st1 8 { 9char a ; 10int b ; 11short c ; 12 }; 13 14struct st2 15 { 16short c ; 17char a ; 18int b ; 19 }; 20 21int main() 22 { 23 cout<<"sizeof(st1) is "<

程序的输出结果为: sizeof(st1) is 12 sizeof(st2) is 8 问题出来了,这两个一样的结构体,为什么sizeof的时候大小不一样呢? 本文的主要目的就是解释明白这一问题。 内存对齐,正是因为内存对齐的影响,导致结果不同。 对于大多数的程序员来说,内存对齐基本上是透明的,这是编译器该干的活,编译器为程序中的每个数据单元安排在合适的位置上,从而导致了相同的变量,不同声明顺序的结构体大小的不同。 那么编译器为什么要进行内存对齐呢?程序1中结构体按常理来理解sizeof(st1)和sizeof(st2)结果都应该是7,4(int) + 2(short) + 1(char) = 7 。经过内存对齐后,结构体的空间反而增大了。 在解释内存对齐的作用前,先来看下内存对齐的规则: 1、对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。 2、在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。 #pragma pack(n) 表示设置为n字节对齐。VC6默认8字节对齐 以程序1为例解释对齐的规则:

C语言内存字节对齐规则20180718

C语言内存字节对齐规则 在C语言面试和考试中经常会遇到内存字节对齐的问题。今天就来对字节对齐的知识进行小结一下。 首先说说为什么要对齐。为了提高效率,计算机从内存中取数据是按照一个固定长度的。以32位机为例,它每次取32个位,也就是4个字节(每字节8个位,计算机基础知识,别说不知道)。字节对齐有什么好处?以int型数据为例,如果它在内存中存放的位置按4字节对齐,也就是说1个int的数据全部落在计算机一次取数的区间内,那么只需要取一次就可以了。如图a-1。如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,这样效率也就降低了。 图:a-1 图:a-2 内存对齐是会浪费一些空间的。但是这种空间上得浪费却可以减少取数的时间。这是典型的一种以空间换时间的做法。空间与时间孰优孰略这个每个人都有自己的看法,但是C 语言既然采取了这种以空间换时间的策略,就必然有它的道理。况且,在存储器越来越便宜的今天,这一点点的空间上的浪费就不算什么了。 需要说明的是,字节对齐不同的编译器可能会采用不同的优化策略,以下以GCC为例讲解结构体的对齐. 一、原则: 1.结构体内成员按自身按自身长度自对齐。

自身长度,如char=1,short=2,int=4,double=8,。所谓自对齐,指的是该成员的起始位置的内存地址必须是它自身长度的整数倍。如int只能以0,4,8这类的地址开始 2.结构体的总大小为结构体的有效对齐值的整数倍 结构体的有效对齐值的确定: 1)当未明确指定时,以结构体中最长的成员的长度为其有效值 2)当用#pragma pack(n)指定时,以n和结构体中最长的成员的长度中较小者为其值。 3)当用__attribute__ ((__packed__))指定长度时,强制按照此值为结构体的有效对齐值 二、例子 1) struct AA{ //结构体的有效对齐值为其中最大的成员即int的长度4 char a; int b; char c; }aa 结果,sizeof(aa)=12 何解?首先假设结构体内存起始地址为0,那么地址的分布如下 0 a 1 2 3 4 b 5 b 6 b 7 b 8 c 9 10 11 char的字对齐长度为1,所以可以在任何地址开始,但是,int自对齐长度为4,必须以4的倍数地址开始。所以,尽管1-3空着,但b也只能从4开始。再加上c后,整个结构体的总长度为9,结构体的有效对齐值为其中最大的成员即int的长度4,所以,结构体的大小向上扩展到12,即9-11的地址空着。 2) //结构体的有效对齐值为其中最大的成员即int的长度4 struct AA{ char a; char c; int b; }aa sizeof(aa)=8,为什么呢 0 a 1 c

结构体对齐方式

结构体对齐方式 结构体(struct)的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。先看下面定义的两个结构体. struct { char a; short b; char c; }S1; struct { char a; char b; short c; }S2; 分别用程序测试得出sizeof(S1)=6 , sizeof(S2)=4 可见,虽然两个结构体所含的元素相同,但因为其中存放的元素类型顺序不一样,所占字节也出现差异。这就是字节对齐原因。通过字节对齐,有助于加快计算机的取数速度,否则就得多花指令周期。 字节对齐原则: 结构体默认的字节对齐一般满足三个准则: 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员自身大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。 通过这三个原则,就不难理解上面两个struct的差异了. 对于struct S1, 为了使short变量满足字节对其准则(2), 即其存储位置相对于结构体首地址的offset是自身大小(short占2个字节)的整数倍,必须在字节a后面填充一个字节以对齐;再由准则(3),为了满足结构体总大小为short大小的整数倍,必须再在c后面填充一个字节。对于struct S2, 却不必如上所述的填充字节,因为其直接顺序存储已经满足对齐准则。 如果将上面两个结构体中的short都改为int(占4个字节), 那么会怎么样呢?程序得出sizeof(S1)=12, sizeof(S2)=8 利用上面的准则,也不难计算得出这样的结果。S1中在a后面填充3个字节、在c后面填充3个字节,这样一共12个字节;S2中在a、b顺序存储之后填充两个字节用以对其,这样一共就8个字节。 当然,在某些时候也可以设置字节对齐方式。这就需要使用 #pragma pack 。 #pragma pack(push) //压栈保存 #pragma pack(1)// 设置1字节对齐 struct { char a; short b; char c; }S1; #pragma pack(pop) // 恢复先前设置 如上所示,将对其方式设为1字节对齐,那么S1就不填充字节,sizeof为各元素所占字节之和即4。这一点在从外部2进制文件中读入struct大小的数据到struct中,是很有用的。 另外,还有如下的一种方式:

C语言内存对齐

解析C语言结构体对齐(内存对齐问题) C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢? 开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐? 有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下): 原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。 原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。) 原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。 这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。 例1:struct { short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof(A) = 6; 这个很好理解,三个short都为2。 sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。 例2:struct A{ int a; char b; short c; }; struct B{ char b; int a; short c; }; sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。 sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。

C语言结构体对齐

C语言结构体对齐 C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢? 开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐? 有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下): 原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。 原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b 里有char,int,double等元素,那b应该从8的整数倍开始存储。) 原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。 这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。 例1:struct { short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof(A) = 6; 这个很好理解,三个short都为2。 sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,

C语言结构体的字节对齐及指定对齐方式

内存中结构体的内存对齐 一、字节对齐作用和原因: 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐,其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit 数据,显然在读取效率上下降很多。 二、字节对齐规则: 四个重要的概念: 1.数据类型自身的对齐值:对于char型的数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4个字节。 2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。 3.指定对齐值:#pragma pack (value)时指定的对齐value。 4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。补充: 1).每个成员分别按自己的方式对齐,并能最小化长度。 2).复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。 3).对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。 #pragma pack(1) struct test { static int a; //static var double m4; char m1; int m3; } #pragma pack() //sizeof(test)=13;

C语言结构体对齐问题

C语言结构体对齐问题 1。几个结构体例子: struct{ short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; sizeof( A)=6, sizeof( B)=8,为什么? 注:sizeof(short)=2,sizeof(long)=4 因为:“成员对齐有一个重要的条件,即每个成员按自己的方式对齐。其对齐的规则是,每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里默认是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。”(引用) 结构体A中有3个short类型变量,各自以2字节对齐,结构体对齐参数按默认的8字节对齐,则a1,a2,a3都取2字节对齐,则sizeof(A)为6,其也是2的整数倍; B中a1为4字节对齐,a2为2字节对齐,结构体默认对齐参数为8,则a1取4字节对齐,a2取2字节对齐,结构体大小6字节,6不为4的整数倍,补空字节,增到8时,符合所有条件,则sizeof(B)为8; 可以设置成对齐的 #pragma pack(1) #pragma pack(push) #pragma pack(1) struct{

short a1; short a2; short a3; }A; struct{ long a1; short a2; }B; #pragma pack(pop) 结果为sizeof( A)=6,sizeof( B)=6 ************************ #pragma pack(8) struct S1{ char a; long b; }; struct S2 { char c; struct S1 d; long long e; }; #pragma pack() sizeof(S2)结果为24.

C语言结构体(struct)常见使用方法

C语言结构体(struct)常见使用方法 基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。 结构体定义: 第一种:只有结构体定义 [cpp]view plain copy 1.struct stuff{ 2.char job[20]; 3.int age; 4.float height; 5.}; 第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义 [cpp]view plain copy 1.//直接带变量名Huqinwei 2.struct stuff{ 3.char job[20]; 4.int age; 5.float height; 6.}Huqinwei; 也许初期看不习惯容易困惑,其实这就相当于: [cpp]view plain copy 1.struct stuff{ 2.char job[20]; 3.int age;

4.float height; 5.}; 6.struct stuff Huqinwei; 第三种:如果该结构体你只用一个变量Huqinwei,而不再需要用 [cpp]view plain copy 1.struct stuff yourname; 去定义第二个变量。 那么,附加变量初始化的结构体定义还可进一步简化出第三种: [cpp]view plain copy 1.struct{ 2.char job[20]; 3.int age; 4.float height; 5.}Huqinwei; 把结构体名称去掉,这样更简洁,不过也不能定义其他同结构体变量了——至少我现在没掌握这种方法。 结构体变量及其内部成员变量的定义及访问: 绕口吧?要分清结构体变量和结构体内部成员变量的概念。 就像刚才的第二种提到的,结构体变量的声明可以用: [cpp]view plain copy 1.struct stuff yourname; 其成员变量的定义可以随声明进行: [cpp]view plain copy 1.struct stuff Huqinwei = {"manager",30,185}; 也可以考虑结构体之间的赋值: [cpp]view plain copy

内存对齐

最近被面试了,打击挺大,问啥啥不会。 举一个很多不会的题中的一个,关于内存对齐的问题,以前也知道点,个人感觉很重要,在这里与同道中人分享下: 很多书籍中都讲到:内存可以看成一个byte数组,我们通过编程语言提供的工具对这个'大数组'中的每个元素进行读写,比如在C中我们可以用指针一次读写一个或者更多个字节,这是我们一般程序员眼中的内存样子。但是从机器角度更具体的说从CPU角度看呢,CPU发出的指令是一个字节一个字节读写内存吗?答案是'否'。CPU是按照'块(chunk)'来读写内存的,块的大小可以是2bytes, 4bytes, 8bytes, 16bytes甚至是32bytes. 这个CPU访问内存采用的块的大小,我们可以称为'内存访问粒度'。 程序员眼中的内存样子: --------------------------------- | | | | | | | | | | | | | | | | | --------------------------------- 0 1 2 3 4 5 6 7 8 9 A B C D E F (地址) CPU眼中的内存样子:(以粒度=4为例) --------------------------------------------- | | | | | | | | | | | | | | | | | | | | --------------------------------------------- 0 1 2 3 4 5 6 7 8 9 A B C D E F (地址) 有了上面的概念,我们来看看粒度对CPU访问内存的影响。 假设这里我们需要的数据分别存储于地址0和地址1起始的连续4个字节的存储器中,我们目的是分别读取这些数据到一个4字节的寄存器中, 如果'内存访问粒度'为1,CPU从地址0开始读取,需要4次访问才能将4个字节读到寄存器中; 同样如果'内存访问粒度'为1,CPU从地址1开始读取,也需要4次访问才能将4个字节读到寄存器中;而且对于这种理想中的''内存访问粒度'为1的CPU,所有地址都是'aligned address'。 如果'内存访问粒度'为2,CPU从地址0开始读取,需要2次访问才能将4个字节读到寄存器中;每次访存都能从'aligned address'起始。 如果'内存访问粒度'为2,CPU从地址1开始读取,相当于内存中数据分布在1,2,3,4三个地址上,由于1不是'aligned address',所以这时CPU要做些其他工作,由于这四个字节分步在三个chunk上,所以CPU需要进行三次访存操作,第一次读取chunk1(即地址0,1上两个字节,而且仅仅地址1上的数据有用),第二次读取chunk2(即地址2,3上两个字节,这两个地址上的数据都有用),最后一次读取chunk3(即地址5,6上两个字节,而且仅仅地址5上的

内存对齐规则

C语言中内存对齐规则讨论(struct) (2012-02-17 17:51:17) 转载▼ 分类:学习 标签: struct union c语言 内存 it 对齐: 现代计算机中内存空间都是按着byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就是需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 对齐的作用: 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存储。其他平台可能没有这种情况,但是最常见的是如果不按照合适其平台的要求对数据进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶数地址开始,如果一个int型(假设为32位)如

果存放在偶数开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次独处的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。 对齐的实现 通常我们写程序的时候,不需要考虑对齐问题,编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对制定数据的对齐方法。缺省情况下,编译器为结构体的每个成员按其自然対界条件分配空间。各个成员按照他们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。自然対界即默认对齐方式,是指按结构体的成员中size最大的成员对齐。 最常见的就是struct数据结构的sizeof的结果出乎意料。 结构体的sizeof的值并不是简单的将其中各个元素所占的字节相加,而是要考虑到存储空间的字节对齐问题 结构体默认的字节对齐准则: 1.结构体变量的首地址能够被其最宽基本类型成员的大 小所整除;

[C++]字节对齐与结构体大小

[C++]字节对齐与结构体大小 说明: 结构体的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。这些问题在平时编程的时候也确实不怎么用到,但在一些笔试面试题目中出是常常出现,对sizeof我们将在另一篇文章中总结,这篇文章我们只总结结构体的sizeof,报着不到黄河心不死的决心,终于完成了总结,也算是小有收获,拿出来于大家分享,如果有什么错误或者没有理解透的地方还望能得到提点,也不至于误导他人。 别忘了这里https://www.wendangku.net/doc/bc15853041.html,/blog/static/30203796201082494026399/ 一、解释 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。 二、准则 其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则: 1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节; 3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。 三、基本概念 字节对齐:计算机存储系统中以Byte为单位存储数据,不同数据类型所占的空间不同,如:整型(int)数据占4个字节,字符型(char)数据占一个字节,短整型(short)数据占两个字节,等等。计算机为了快速的读写数据,默认情况下将数据存放在某个地址的起始位置,如:整型数据(int)默认存储在地址能被4整除的起始位置,字符型数据(char)可以存放在任何地址位置(被1整除),短整型(short)数据存储

内存对齐问题的完美解释

解析C语言中的sizeof 一、sizeof的概念 sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。 二、sizeof的使用方法 1、用于数据类型 sizeof使用形式:sizeof(type) 数据类型必须用括号括住。如sizeof(int)。 2、用于变量 sizeof使用形式:sizeof(var_name)或sizeof var_name 变量名可以不用括号括住。如sizeof (var_name),sizeof var_name等都是正确形式。带括号的用法更普遍,大多数程序员采用这种形式。 注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。 如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式。 三、sizeof的结果 sizeof操作符的结果类型是size_t,它在头文件 中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。 1、若操作数具有类型char、unsigned char或signed char,其结果等于1。 ANSI C正式规定字符类型为1字节。 2、int、unsigned int 、short int、unsigned short 、long int 、unsigned long 、float、double、long double类型的sizeof 在ANSI C 中没有具体规定,大小依赖于实现,一般可能分别为2、2、2、2、4、4、4、8、

相关文档