天天看点

将32位代码向64位平台移植的注意事项3

联合体问题(Union)

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

  例3:

typedef struct {

 unsigned short bom;

 unsigned short cnt;

 union {

  unsigned long bytes;

  unsigned short len[2];

 } size;

} _ucheader_t;

  要在LP64上运行,代码中的unsigned long应改为unsigned int。要在所有代码中仔细检查联合体,以确认所有的数据成员在LP64中都为同等长度。

  字节序问题(Endian)

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

  例4:

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;

}

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

将32位代码向64位平台移植的注意事项3

X

  表3说明了为什么在不同的字节序系统中,会因截断问题而产生不同的答案。在小尾字节序中,被截断的高位地址中全为0,所以答案仍为2;而在大尾字节序中,被截断的高位地址中包含值2,这样就导致结果为0,所以在两种情况下,截断都是一种bug。但要意识到,小尾字节序会隐藏小数值的截断错误,而这个错误只有在移植到大尾字节序系统上时才可能被发现。

继续阅读