不同数据模型下,各数据类型的位数:
Type \ Model | LP32 | IPL32 | LP64 | ILP64 | LLP64 |
char | 8 | 8 | 8 | 8 | 8 |
short | 16 | 16 | 16 | 16 | 16 |
int | 16 | 32 | 32 | 64 | 32 |
long | 32 | 32 | 64 | 64 | 32 |
long long | 64 | 64 | 64 | 64 | 64 |
pointer | 32 | 32 | 64 | 64 | 64 |
在这张表中,LP32和ILP32是32位平台上的字长模型,LP64,ILP64,LLP64是64位平台上的字长模型。
LP32指long和pointer是32位的,
ILP32指int,long和pointer是32位的,
LP64指long和pointer是64位,
ILP64指int,long,pointer是64位,
LLP64指long long和pointer是64位的。
常见32位环境一般仅涉及"ILP32"数据模型;而64位环境则使用不同的数据模型。现今所有64位的类Unix平台均使用LP64数据模型,而64位Windows使用LLP64数据模型。
以上 3 个 64 位模型(LP64、LLP64 和 ILP64)之间的区别在于非浮点数据类型。当一个或多个 C 数据类型的宽度从一种模型变换成另外一种模型时,应用程序可能会受到很多方面的影响。这些影响主要可以分为两类:
- 数据对象的大小。编译器按照自然边界对数据类型进行对齐;换而言之,32 位的数据类型在 64 位系统上要按照 32 位边界进行对齐,而 64 位的数据类型在 64 位系统上则要按照 64 位边界进行对齐。这意味着诸如结构或联合之类的数据对象的大小在 32 位和 64 位系统上是不同的。
- 基本数据类型的大小。通常关于基本数据类型之间关系的假设在 64 位数据模型上都已经无效了。依赖于这些关系的应用程序在 64 位平台上编译也会失败。例如,
sizeof (int) = sizeof (long) = sizeof (pointer)
的假设对于 ILP32 数据模型有效,但是对于其他数据模型就无效了。
总之,编译器要按照自然边界对数据类型进行对齐,这意味着编译器会进行 “填充”,从而强制进行这种方式的对齐,就像是在 C 结构和联合中所做的一样。结构或联合的成员是根据最宽的成员进行对齐的。
数据类型转换原则:
结构体对齐,默认对齐原则:
1.数据类型对齐值:
char型数据自身对齐值为1
short为2,int、float为4,double为8(windows)
解释:
char变量只要有一个空余的字节即可存放
short要求首地址能被2整除,int、float、double同理
2.结构体的对齐值:
其成员中自身对齐值最大的那个值。
解释:
结构体最终对齐按照数据成员中最长的类型的整数倍
指定对齐原则:
使用#pragma pack改变默认对齐原则
格式:
#pragma pack (value)时的指定对齐值value。
结构体最终对齐按照指定对齐值的整数倍
注意:
1.value只能是:1 2 4 8等
2.指定对齐值与数据类型对齐值相比取较小值
如:如果指定对齐值:
设为1:则short、int、float等均为1
设为2:则char仍为1,short为2,int 变为2