C语言32位和64位编程注意事项

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

Data type

Data length(32bit)

Data length(64bit)

Signed

char

8

8

Y

unsigned char

8

8

N

short

16

16

Y

unsigned short

16

16

N

int

32

32

Y

unsigned int

32

32

N

long

32

64

Y

unsigned long

32

64

N

long long

64

64

Y

point

32

64

N

size_t

32

64

N

ssize_t

32

64

Y

off_t

32

64

Y

2.向64位移植代码时的所有问题差不多都可以总结出一个简单的规律:千万不要认为int、long、指针的长度一样。

3.strlen返回size_t(它在LP64中是unsigned long),当赋值给一个int时,截断是必然发生的。而通常,截断只会在str的长度大于2GB时才会发生,这种情况在程序中一般不会出现。

4.那些以十六进制或二进制表示的常量,通常都是32位的。例如,无符号32位常量0xFFFFFFFF通常用来测试是否为-1:

#define INVALID_POINTER_VALUE 0xFFFFFFFF

然而,在64位系统中,这个值不是-1,而是4294967295;在64位系统中,-1正确的值应为0xFFFFFFFFFFFFFFFF。要避免这个问题,在声明常量时,使用const,并且带上signed或unsigned。

const signed int INVALID_POINTER_VALUE = 0xFFFFFFFF;

这行代码将会在32位和64位系统上都运行正常。

5.联合体问题(Union)
当联合本中混有不同长度的数据类型时,可能会导致问题。下面是一个常见的开源代码包,可在ILP32却不可在LP64环境下运行。代码假定长度为2的unsigned short数组,占用了与long同样的空间,可这在LP64平台上却不正确。

typedef struct {
 unsigned short bom;
 unsigned short cnt;
 union {
unsigned long bytes;
unsigned short len[2];
 } size;
} _ucheader_t;

6.符号扩展
要避免有符号数与无符号数的算术运算。在把int与long数值作对比时,此时产生的数据提升在LP64和ILP32中是有差异的。因为是符号位扩展,所以这个问题很难被发现,只有保证两端的操作数均为signed或均为unsigned,才能从根本上防止此问题的发生。

long k;
int i = -2;
unsigned int j = 1;
k = i + j;
printf("Answer: %ld\n", k);

你无法期望答案是-1,然而,当你在LP64环境中编译此程序时,答案会是4294967295。原因在于表达式(i+j)是一个 unsigned int表达式,但把它赋值给k时,符号位没有被扩展。要解决这个问题,两端的操作数只要均为signed或均为unsigned就可。

7.字节序问题(Endian)
因64位平台的差异,在移植32位程序时,可能会失败,原因可归咎于机器上字节序的不同。Intel、IBM PC等CISC芯片使用的是Little-endian,而Apple之类的RISC芯片使用的是Big-endian;小尾字节序(Little- endian)通常会隐藏移植过程中的截断bug。

long k;
int *ptr;
int main(void)
{
 k = 2 ;
 ptr = &k;
 printf("k has the value %ld, value pointed to by ptr is %ld\n", k, *ptr);
 return 0;
}

这是一个有此问题的明显例子,一个声明指向int的指针,却不经意间指向了long。在ILP32上,这段代码打印出2,因为int与long长度一样。但到了LP64上,因为int与long的长度不一,而导致指针被截断。不管怎么说,在小尾字节序的系统中,代码依旧会给出k的正确答案2,但在大尾字节序(Big-endian)系统中,k的值却是0。

8.移植到64位平台之后的性能降低
当代码移植到64位平台之后,也许发现性能实际上降低了。原因与在LP64中的指针长度和数据大小有关,并由此引发的缓存命中率降低、数据结构膨胀、数据对齐等问题。 

9.64位体系结构出现的原因在于应用需要更大的寻址空间。这些应用可能是高性能的服务器,数据管理系统,CAD或者游戏。这些应用将从64位地址空间和更多地寄存器中得到大量的性能提升。需要大量的内存的应用可以期待着有更高的性能提升。

10.打开和关闭编译时警告:

-w的意思是关闭编译时的警告,也就是编译后不显示任何warning,因为有时在编译之后编译器会显示一些例如数据转换之类的警告,这些警告是我们平时可以忽略的。

-Wall选项意思是编译后显示所有警告。

-W选项类似-Wall,会显示警告,但是只显示编译器认为会出现错误的警告。

在编译一些项目的时候可以-W和-Wall选项一起使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值