数据模型(LP32 ILP32 LP64 LLP64 ILP64 )

数据模型(LP32 ILP32 LP64 LLP64 ILP64 )

 

32位环境涉及"ILP32"数据模型,是因为C数据类型为32位的int、long、指针。而64位环境使用不同的数据模型,此时的long和指针已为64位,故称作"LP64"数据模型。

现今所有64位的类Unix平台均使用LP64数据模型,而64位Windows使用LLP64数据模型,除了指针是64位,其他基本类型都没有变。

 

Data Type ILP32 LP32 ILP64 LP64 LLP64
宏定义   _     _     _   __LP64__ __LLP64__
平台 Win32 API / Unix 和 Unix 类的系统 (Linux,Mac OS X) Win16 API   Unix 和 Unix 类的系统 (Linux,Mac OS X) Win64 API
char 8 8 8 8 8
short 16 16 16 16 16
int 32 32 64 32 32
long 32 32 64 64 32
long long 64 64 64 64 64
pointer 32 32 64 64 64

 

在这张表中,LP64,ILP64,LLP64是64位平台上的字长模型,ILP32和LP32是32位平台上的字长模型。

LP64意思是long和pointer是64位,

ILP64指int,long,pointer是64位,

LLP64指long long和pointer是64-bit的。

ILP32指int,long和pointer是32位的,

LP32指long和pointer是32位的。

 

float 都是4字节;
double 都是8字节;(C中直接写小数,默认是double型)

 

这 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

 

移位运算
左移<<
        将一个数的二进制位左移,高位丢弃,低位补0
        例:a = a<<2 将a的二进制数左移2位,右补0
        若a=15,即二进制数0 0 0 01111
        左移2位得0 011110 0,(十进制数60)
>>算术右移
        有符号数,如果为正数,则左边移入0,右边丢弃
        如果为负数,左边移入1,右边丢弃
>>逻辑右移
        不关心正数、负数,左边均移入0,右边丢弃
        算术或者逻辑右移,由编译器决定

 

博主今天在写代码的时候遇到一个奇怪的问题,程序的要求是实现一个int的移位操作,不管左移还是右移,空出来的位置通通置0即逻辑移位。一开始没注意太多直接用了<<和>>移位操作符,结果却发现实现是错误的==!
经过查证发现,c语言中的移位操作符,在左移时执行的是逻辑移位,在右移时执行的是算术移位。那怎么用>>实现右移操作呢?
又经过查证得知,无符号数的移位操作都是执行的逻辑移位。那么要想用>>实现逻辑右移就可以将操作数强制类型转化为unsigned类型,如下:

int a = 0xfffffffe;
int b = (unsigned int)a >> 1;


执行的结果是2147483647即7fffffff,可见其右移后左端补的是0。
综上:C语言中移位操作符实现的是逻辑左移和算术右移,但是算术左移和逻辑左移的效果相同,算术右移和逻辑右移的效果不同,要实现逻辑右移可将操作数强制类型转化为无符号数

 

posted @ 2017-09-30 14:23  lsgxeva  阅读(16163)  评论(1编辑  收藏  举报