在32位、64位系统当中,唯一改变的是指针的长度;在32位系统当中是4个字节、64位则是8个字节。所谓的32位、64位,这个指的是寄存器的位宽。
32位平台下结果:
64位平台下结果:
一、下面几点是值得大家注意的:
1、关于 int 的取值范围,缺省的int数值范围是由编译器设计者决定的,通常都是机器最为自然高效的位数。甚至,我们在32位的机器上,前提没有什么指令可以高效的的处理更短的整型值,我们可以将short、int、long都设置成32位。
2、浮点数在缺省的情况下 表示的是double,但是你可以在后面加上L/l或者F/f来表明其long double 或者是 float数据类型。
3、当移植问题比较重要的时候,最佳的方案就是将使用的char值限制在 unsigned char 和 signed char取值范围之间。并且只当显示的声明signed char 和unsigned char时, 才对其执行算数运算;这是考虑到char虽然在设计上是为了存储字符,但是在很多实际应用当中,尤其是嵌入式产品设计当中,本质上我们用它存储小整数,不同的编译器会将缺省的char视为unsigned或者是
signed,但是有些机器在处理signed char上得心应手,硬性将其变为unsigned,效率可能受损。所以还要有些矛盾的指出,全部显示的声明为 unsigned char 和 signed char 并不是上上之策。
二、在32位操作系统下:
1:整形
int 4字节
longint 4字节
shortint 2字节
unsignedint 4字节
unsignedlong int 4字节
unsignedshort int 2字节
2:字符型
char 1字节
unsignedchar 1字节
3:浮点型
float 4字节
double 8字节
longdouble 8字节
unsigned longdouble 8字节
unsigneddouble 4字节
4:字符串型
string 32字节
5:指针类型
所有类型的指针都是 4字节
6:函数
除了void型。其他都函数占有的字节数等于函数的返回类型所占有的字节数。与函数体内部无关。
如:float fun(){ return 2;}
sizeof(fun())= 8
7:结构体、类
内部各数据类型占用之和,注意边界对齐。
如: struct fun1
{
int a; //4
double b; //8
char c; //1
};
sizeof(fun1)=24
truct fun2
{
int a; //4
char c; //1
};
sizeof(fun2)=8
特殊:
structfun3
{
string a; //32
char b,c,d; //3
}b;
sizeof(fun3)=36
8:联合体union
取其中占有字节数最大的数据类型所占有的字节数。
三、对于64位操作系统中应该注意以下几点:
64 位的优点:64 位的应用程序可以直接访问 4EB 的内存和文件大小最大达到4 EB(2 的 63 次幂);可以访问大型数据库。本文介绍的是64位下C语言开发程序注意事项。
1. 32 位和 64 位C数据类型
32和64位C语言内置数据类型,如下表所示:
上表中第一行的大写字母和数字含义如下所示:
I表示:int类型
L表示:long类型
P表示:pointer指针类型
32表示:32位系统
64表示64位系统
如:LP64表示,在64位系统下的long类型和pointer类型长度为64位。
64位Linux 使用了 LP64 标准,即:long类型和pointer类型长度为64位,其他类型的长度和32位系统下相同类型的长度相同,32位和64位下类型的长度比较见上图的蓝色部分。
下图为在32和64位linux系统下使用sizeof检测出的数据类型的长度。
32位平台下结果:
64位平台下结果:
2. 64系统下开发注意事项:
2.1 格式化字符串:long使用%ld,指针使用%p,例如:
1. char *ptr = &something;
2. printf (%x\n", ptr);
上面的代码在 64
位系统上不正确,只显示低 4字节的内容。正确的方法是:使用 %p,如下:
1. char *ptr = &something;
2. printf (%p\n", ptr);
2.2 数字常量:常量要加L
例1,常数 0xFFFFFFFF 是一个有符号的 long 类型。在 32 位系统上,这会将所有位都置位(每位全为 1),但是在 64 位系统上,只有低 32 位被置位了,结果是这个值是 0x00000000FFFFFFFF。
例2,在下面的代码中,a 的最大值可以是 31。这是因为 1 << a 是 int 类型的。
1. long l = 1 << a;
要在 64位系统上进行位移,应使用 1L,如下所示:
1. long l = 1L << a;
2.3 符号扩展:避免有符号数与无符号数运算,例如:
1. int i = -2;
2. unsigned int j = 1;
3. long l = i + j;
4. printf("Answer: %ld\n",l);
32位下是-1,在64位下是4294967295。原因在于表达式(i+j)是一个unsignedint表达式,但把它赋值给k时,符号位没有被扩展。要解决这个问题,两端的操作数只要均为signed或均为unsigned就可。
2.4 转换截断(只要是位数大的数据类型转换成位数小的数据类型时都会出现截断效应,会产生数据误差,在不同数据类型进行运算时,系统一般会自动进行数据类型转换,但此时是位数小的数据类型自动转换成位数大的数据类型,这样不会产生数据误差):
转换截断发生在把long转换成int时,如下例:
1. int length = (int) strlen(str);
strlen返回size_t(它在LP64中是unsignedlong),当赋值给一个int时,截断是必然发生的。而通常,截断只会在str的长度大于2GB时才会发生,这种情况在程序中一般不会出现。虽然如此,也应该尽量使用适当的多态类型(如size_t、uintptr_t等等)。
2.5 赋值:
不要交换使用 int 和 long 类型,例如:
1. int i;
2. long int a = l;
3. i = a;
不要使用 int 类型来存储指针,例如:
1. unsigned int i, *ptr;
2. i = (unsigned) ptr;
不要使用指针来存放 int 类型的值。例如:
1. int *ptr;
2. int i;
3. ptr = (int *) i;
2.6 移植到64位环境下的性能:
移植到64位平台后,性能实际上降低了。原因是64位中的指针长度和数据大小有关,并由此引发的缓存命中率降低、数据对齐等问题。通过改变结构中数据排列的先后顺序,会因为少了填充数据,存储空间也随之减少。如:
2.7 程序中链接到的库要使用64位的库。
由上可见所有的问题都是由long和指针长度改变引起,在开发过程中只有牢记long和指针类型的长度。