深入理解计算机系统笔记二

   对于自动驾驶,特别是嵌入式开发板上移植程序来说,用某个确定大小的表示来编码数据类型非常重要。例如,当编写程序,使得机器能够按照一个标准协议在因特网上通信时,让数据类型与协议指定的数据类型兼容是非常重要的。不过现在64位系统已经比较普及,不像以前处于过渡阶段。特别是long型,在不同的机器上有不同的取值范围,而实际上C语言标准只指定了每种数据类型的最小范围,而不是确定的范围。虽然我们可以选择与大多数机器上的标准表示兼容的数据类型,但是这也不能保证可移植性。

    从32位到64位,根本性的区别在于两种数据类型发生了变化:long和pointer。在32位环境下,两者长度都是32位,也就是4个字节;而在64位环境下都是8个字节。所以当你把pointer或者long型数据赋给int型时,会发生数据截断(data truncation)。32位应用的数据模型我们称作ILP32(之所以这样命名,是因为int,long,pointer都是32位),而64位应用则采用LP64模型(意味着long,pointer变成64位了,其他的不变)。在当前的32位环境下,我们可以认为int,long,pointer是等价的,因为它们占用相同的字节,于是就有很多混用的情况;但是到了64位的时代,long和Poniter的大小都改变了,原来的假设不再成立。

1.1int和pointer转换问题

因为integer与pointer大小相同,所以32位代码中常常把pointer转换为int或者unsigned int,以便算术运算。为了移植,你可以把pointer转换为unsigned long,因为long和pointer都是等长的,无论是在ILP32或LP64。但是,为了使代码更清晰,推荐用uintptr_t,uintptr_t和intptr_t都需要包含头文件inttypes.h。
例如:下面代码在64位环境下编译出错:

char *p = &something;
p = (char *) ((int)p & PAGEOFFSET);
 
% cc ..
warning: conversion of pointer loses bits

改用uintptr_t后,无论是32位或者64位都没问题:

char *p = &something;
p = (char *) ((uintptr_t)p & PAGEOFFSET);

1.2 int和long转换

int A = 0;
long B = 0;
long C = 0;
...
A = B + C;
 
 
% cc
warning: assignment of 64-bit integer to 32-bit integer

1.3 结构体字节对齐及大小问题

这个问题我是切切实实吃个亏的,特别要注意结构体中有long类型的(无人车系统里各个传感器数据包中的时间戳unsigned long long)

struct T 
{
int i; 
long j; 
int k; 
char *p;
};

这个时候需要注意结构体中不同数据类型的位置排布

struct T
{
char *p;
long j;
int i;
int k;
};

此时,无需扩展,sizeof(T)=8+8+4+4=24.

猜你喜欢

转载自blog.csdn.net/lucky_greenegg/article/details/81436417
今日推荐