C++是一个强类型的语言,在编码的过程中,一定要时刻注意到你操作对象的类型。
很多类型不一致的隐式赋值,不仅仅造成了我们的代码很难跨平台,还可能是导致莫名奇妙bug的隐患。
如果确实需要类型的转换,请显式的转换数据类型, static_cast等等。
当前我们在Solaris下面使用的forteC6.2编译器,这个编译器本身是一个比较老的编译器,很多C++规范支持都不够好,在加上Solaris操作系统特殊的内存使用机制,让我们养成了一些写代码的不规范的习惯。
在forteC6.2编译器可以编译通过的代码不意味着代码是标准的。
在Solaris操作系统上面运行正常的代码不意味着代码是正确的。
多想一下,多在其他平台上面编译一下,对我们代码的正确性、可靠性、可移植性,以及我们的技能都会有莫大的提高。
注:
本版规范是初次版本,后续会添加修正后再次发布,欢迎大家提出更有效的问题解决办法或者编码规范。有什么问题请反馈给我(庄乾锋 61576),谢谢
版本信息:2008-6-30
1 pragma pack 问题
不兼容代码:
#pragma pack(1)
...
#pragma pack(4)
可能导致的问题:
1. 是没有可移植性,
2. 是不能确保在嵌套的环境下也能正常使用。
3. 在 64 位平台上,会产生 core dump。
修改方法:
在IA64的平台上面,使用宏开关SUSE_IA64分隔。在C++中如果无特殊需要,建议不要操作二进制字节流,不要对pragma pack,直接使用对应的对象操作即可。
#ifdef SUSE_IA64
#pragma pack(push,1)
#else
#pragma pack(1)
#endif
...<define your struct here>
#ifdef SUSE_IA64
#pragma pack(pop)
#else
#pragma pack(4) ----此处的代码写的非常槽糕,如果想恢复原来,使用pragma pack(pop)
#endif
2 用平台无关类型替换特定类型
(a)指针类型
不兼容代码:
#ifdef SUSE_IA64
switch (reinterpret_cast<long>(pvArg))
#else
switch (reinterpret_cast<int>(pvArg))
#endif
可能导致的问题:
指针长度在 32 位机器上使 32 位的,而在 64 位机器上是64 位的,使用
int和 long 强制转换容易出错,且不具备可移植性,建议使用intptr_t和uintptr_t(unsigned)。
修改方法:
switch (reinterpret_cast<intptr_t>(pvArg))
(b)使用STL内置数据类型
用STL内置数据类型string::size_type 替换int/long
错误代码:
string fdn = “www.sina.com”;
unsigned int pos = fdn.rfind('.');
可能导致的问题:
rfind 的函数原型是:
string::size_type
rfind(const basic_string& __str, size_type __pos = npos) const
使用上述代码导致了隐式的类型转换,可能导致数据丢失。
修改方法:
string::size_type pos = fdn.rfind('.');
(c) 使用系统定义类型
错误代码:
long localTime = 0;
可能导致的问题:
在某些情况下,如指针,时间等需要随系统的迁移而改变变量的长度的。可以采用系统定义的一些类型。如果使用 int 类型,在 32 位和 64 位系统中都是 32 位的,不具备可移植性。常用类型见下表。
Type | Purpose |
clock_t | Represents the system times in clock ticks. |
dev_t | Used for device numbers. |
off_t | Used for file sizes and offsets. |
ptrdiff_t | The signed integral type for the result of subtracting two pointers. |
size_t | The size, int bytes, of objects in memory. |
ssize_t | Used by functins that return a count of bytes or an error indication |
time_t | Used for time in seconds. |
修改方法:
#include <sys/types.h>
time_t localTime = 0;
(d)用 int32_t 类型统一变量宽度
不兼容代码
32位版本为long, 64位版本为int, 统一修改为int32_t/uint32_t (unsigned)
#ifdef SUSE_IA64
const unsigned int _neObjId,
#else
const unsigned long _neObjId,
#endif
可能导致的问题:
在 LP64 模型中(目前我们的 64 位机器就使用这个模型)。long 是 64 位的,而在 ILP32 位系统中,long 是 32 位的。在 C99 标准中定义了这几个新的统一长度的类型: int8_t, int16_t, int32_t, int64_t 等。
修改方法:
#include <inttypes>
const uint32_t _neObjId,
(e)通讯协议相关类型
通讯协议相关的, 考虑与原系统兼容性, 必须保持原来的32位通信协议栈。
原32位版本中的long全部修改为int32_t
不兼容代码
#ifdef SUSE_IA64
/* [Keyword] */
int MOCId;
int MOIIdLength
int measTypesLength;
#else
long MOCId;
long MOIIdLength
long measTypesLength;
#endif
修改方法:
#include <inttypes>
int32_t MOCId;
int32_t MOIIdLength
int32_t measTypesLength;
(a)CORBA相关数据类型
与CORBA交互时尽量使用CORBA定义的数据类型。比如CORBA::Ulong在64位上仍然是32位。下面是对照表,左侧是IDL数据类型,右侧是TAO对应数据类型:
boolean | CORBA::Boolean |
char | CORBA::Char |
octet | CORBA::Octet |
short | CORBA::Short |
Unsigned short | CORBA::UShort |
long | CORBA::Long |
Unsigned long | CORBA::ULong |
long long | CORBA::LongLong |
Unsigned long long | CORBA::ULongLong |
wchar | CORBA::WChar |
float | CORBA::Float |
double | CORBA::Double |
long double | CORBA::LongDouble |
不兼容代码
#ifdef SUSE_IA64
CORBA::ULong k=0;
#else
long k=0;
#endif
修改方法:
CORBA::ULong k=0;