12可移植性(兼容性)
来源:互联网 发布:python datetime 时区 编辑:程序博客网 时间:2024/05/22 17:46
12可移植性(兼容性)
本章讨论C++可移植性问题主要关注:32位移植到64位,不同CPU架构之间的移植。
移植中一些关键问题如下:
1. 指针截断
2. 数据类型字节对齐
3. 对内存地址的错误假设
4. 对复合数据类型成员地址的错误假设
5. 大小端,网络字节序问题
建议12.1 不直接使用C++的基本数据类型,不要假定其存储尺寸长度
说明:C++标准没有明确基本数据类型的大小与存储格式,这些基本类型包括:short,int, long, long
long, float double等。这些基本数据类型在不同的编译器中,实现有所不同,如:
long类型在32位编译模式下为4字节长度,在64位编译模式下为8字节长度。
所以建议不要直接使用基本数据类型。推荐如下两种使用方式:
1、重定义基本数据类型
typedef int32_t int;
typedef int64_t long long;
使用重定义后的基本类型好处是:如果程序需要移植,可以大大减少移植的工作量。
2、使用C99标准中定义的标准类型
int64_t my_value = 0x123456789LL;
uint64_t my_mask = 3ULL << 48;
使用这些标准类型长度的好处是,它们规定了固定的长度,这个长度不会随编译器变化而变化,所以
我们可以放心的使用。
建议12.2 避免指针截断
说明:指针截断是从32位移植到64位系统时,经常会碰到的问题。
int *i = &int_val;
short *w = (short*)((int)i + 2);
上面的代码在32位环境下运行是没有问题的,但在64位环境下,发生了地址截断:无法把64位长的数
据接到32位的数据空间里面。
上面的代码中可以使用intptr_t类型解决:
int *i = &int_val;
short *w = (short*)((intptr_t)i + 2);
建议12.3 注意数据类型对齐问题
说明:需要对结构对齐加以留心,尤其是对于存储在磁盘上的结构体。
在64位系统中,任何拥有int64_t/uint64_t成员的类/结构体将默认被处理为8字节对齐。如果32位和64 位
代码共用磁盘上的结构体,需要确保两种体系结构下的结构体的一致对齐。
另外,大多数编译器提供了调整结构体对齐的方案:
gcc 中可使用__attribute__((packed)),MSVC 提供了#pragma pack()和__declspec(align()) 。
由于各个平台和编译器的不同,所以在不同编译器与平台移植代码时,一定要特别关注编译器关于对
齐的参数设置与默认值。因为字节对齐不仅影响性能,而且会导致一些不可预知的问题。
建议12.4 在涉及网络字节序处理时,要注意进行网络字节序与本地字节序的转换
说明:小端法(Little-Endian)
低位字节排放在内存的低地址端即起始地址,高位字节排放在内存的高地址端。
大端法(Big-Endian)
高位字节排放在内存的低地址端即起始地址,低位字节排放在内存的高地址端。
不同cpu平台上字节序通常也不一样:
X86、AMD64平台使用小端法、而HP-IA, IBM AIX的CPU采用的是大端法。
而网络字节序是大端法,如常见网络发送的码流。
涉及网络字节需要注意处理网络字节序与本地字节序的转换,即使本地字节序采用的也是大端法,为
了程序可移植性,建议也调用转换函数进行转换。
库函数提供了16,32位整型int的网络字节序与本地字节序的转换函数:
htonl, htons, ntohl, ntohs - convert values between host and network byte order
建议12.5 避免无符号数与有符号数的转换
说明:不同的国际标准(ANSI C/ISO C++等)对隐式转换有符号和无符号类型的规则不同,有可能导致
不同的执行结果。
unsigned short usNumber = xxx;
long lNum = usNumber;
将unsigned short赋值给long需要经过两次类型转换,ANSI标准中没有规定多次类型转换的顺序。大多
数编译器(例如VC)在高位优先填充0,按照下面的顺序进行转换:
lNum = (long) (unsigned long) usNumber;
个别编译器(例如BSD的一些编译器)在高位优先填充1,即使用下面的顺序进行转换:
lNum = (long) (signed short) usNumber;
如果是后一种转换顺序,并且正好usNumber 的高位为1,则首先被转换成一个负数的long,接着转换成
unsigned long时就成了很大的数。
usNumber永远不可能为负数,没有必要使用signed修饰。
修改办法是定义lNum的类型为unsigned long,并更改名字为ulNum:
unsigned short usNumber = xxx;
unsigned long ulNum = usNumber;
尽量避免无符号数与有符号数的转换,特别是长度不同数值的类型转换。请首先考虑设计上是否需要
这种转换。
建议12.6 创建64 位常量时使用LL 或ULL 作为后缀
说明:指定LL或ULL后缀说明,能让代码更加清晰。
int64_t my_value = 0x123456789LL;
uint64_t my_mask = 3ULL << 48;
尤其是在>>操作时,无符号与有符号有很大差异的,如果操作数是无符号数,则右移操作符>>,从左
边开始插入0, 否则插入符号位的拷贝或者插入0 ,这由编译器决定。
建议12.7 区分sizeof(void *)和sizeof(int)
说明:64位下sizeof(void *) != sizeof(int),而在32位下是相同的。
如果需要一个指针大小的整数请使用intptr_t。
建议12.8 编译器,操作系统相关的代码独立出来
说明:为了程序的可移植性,建议将编译器,操作系统相关的代码从产品代码中独立出来。
编译器特有的东西,如gcc的编译参数__thread, __attribute__等,如果需要做到支持多个平台,需
要封装为宏或函数。
例如gcc的__thread对应的VC开关为__declspec(thread)
__thread int number;
__declspec(thread) int number;
均表示number为线程私有存储变量,可采用如下宏来封装:
#ifdef WIN32
#define THREAD __declspec(thread)
#else
#define THREAD __thread
#endif
THREAD int number;
- 12可移植性(兼容性)
- 正确性、健壮性、可靠性、效率、易用性、可读性(可理解性)、可扩展性、可复 用性、兼容性、可移植性
- Linux 可移植性(软件可移植)
- 可移植性设计
- 可移植性
- 数据类型 可移植性
- 可移植性
- CSS+JQuery提示框----------纯手工打造、兼容性还哦可、可移植任何项目
- Java 的可移植性
- j2me可移植性总结
- LINUX内核可移植性
- 六个维度:可移植性
- 1.3.5 可移植性
- Maven 3 可移植性
- linux的可移植性
- Atitit.常用语言的常用内部api 以及API兼容性对源码级别可移植的重要性 总结
- 关于JAVA的可移植性
- 关于可移植性的一点唠叨
- android 图片平铺实现
- C++编程规范 10并发
- 鸡蛋饭
- C++编程规范 11风格
- [转]浅析PageRank算法
- 12可移植性(兼容性)
- 13全球化
- 指针常量与常量指针
- 14业界编程规范和书籍
- 四种常用HTML5移动应用框架的比较
- 公告:CSDN博客频道推出文章目录功能
- java定时备份mysql,定时ftp上传,下载,删除,重命名,文件(改)
- 收集广州周边徒步线路
- 编译原理