AIX 编译器 13.1.3 对 c++ 的双重转换不正确
Incorrect double conversion by AIX compiler 13.1.3 for c++
我们将 char* 数组中的数据转换为 double,如下面的函数所示:
double getDouble(const char* szData, const size_t dataLength)
{
double res = 0;
if(dataLength == 8)
{
ub8 doubleData = *(ub8*)(szData);
doubleData = ntohll(doubleData);
double* pDoubleData = (double*)(&doubleData);
res = *pDoubleData;
}
return res;
}
ub8 大小为 8 字节,unsigned long long。
double 值 -1.1512299550195975 转换为 3.6975400899608046。但输入和输出应该相等(等于-1.1512299550195975)。这种情况只发生在 AIX 中。在其他平台上我们得到正确的结果。
我们的项目使用优化级别 O2。如果我将优化级别用作 O1 ,则数据会正确转换。
你能帮我吗,你怎么看,为什么转换对于优化级别 O1 是正确的,为什么它对于优化级别 O2 是不正确的?可能我应该在编译中关闭或打开 aix 的某些标志?谢谢你。 Aix编译器版本是13.1.3.
我们从二进制文件中得到了char数组格式的double值。我们从 oracle 数据库的事务日志中解析数据。而oracle写的,比如double值是'40 0d 94 8f e6 10 3e 93'我们应该把double类型的值转换成'-1,1512299550195975'。但是在唯一的 aix 中,我们得到 '3,6975400899608046' 不正确的值
您的实施依赖于未定义的行为,特别是违反了严格的别名规则,正如有人评论的那样。
这就是为什么有时它可以工作(没有优化)有时不能。
为避免违反严格别名,您可以使用以下方法之一:
仅在 C 中(不是 C++,更多信息 here):
typedef union swap64{
unsigned long long u64;
double d64;
}swap64;
swap64 s;
memcpy(s.u64, szData, sizeof(swap64));
s.u64=ntohll(s.u64);
//Following line is UB in C++, but not in C:
return s.d64;
或没有 UB(代码在 C++ 和 C 中均有效):
unsigned long long u64;
double d64;
//Most compilers will remove the memcpy calls and replace them by simpler instructions
memcpy(&u64, szData, sizeof(u64));
u64=ntohll(u64);
memcpy(&d64, &u64, sizeof(u64));
return d64;
我们将 char* 数组中的数据转换为 double,如下面的函数所示:
double getDouble(const char* szData, const size_t dataLength)
{
double res = 0;
if(dataLength == 8)
{
ub8 doubleData = *(ub8*)(szData);
doubleData = ntohll(doubleData);
double* pDoubleData = (double*)(&doubleData);
res = *pDoubleData;
}
return res;
}
ub8 大小为 8 字节,unsigned long long。 double 值 -1.1512299550195975 转换为 3.6975400899608046。但输入和输出应该相等(等于-1.1512299550195975)。这种情况只发生在 AIX 中。在其他平台上我们得到正确的结果。
我们的项目使用优化级别 O2。如果我将优化级别用作 O1 ,则数据会正确转换。 你能帮我吗,你怎么看,为什么转换对于优化级别 O1 是正确的,为什么它对于优化级别 O2 是不正确的?可能我应该在编译中关闭或打开 aix 的某些标志?谢谢你。 Aix编译器版本是13.1.3.
我们从二进制文件中得到了char数组格式的double值。我们从 oracle 数据库的事务日志中解析数据。而oracle写的,比如double值是'40 0d 94 8f e6 10 3e 93'我们应该把double类型的值转换成'-1,1512299550195975'。但是在唯一的 aix 中,我们得到 '3,6975400899608046' 不正确的值
您的实施依赖于未定义的行为,特别是违反了严格的别名规则,正如有人评论的那样。
这就是为什么有时它可以工作(没有优化)有时不能。
为避免违反严格别名,您可以使用以下方法之一:
仅在 C 中(不是 C++,更多信息 here):
typedef union swap64{
unsigned long long u64;
double d64;
}swap64;
swap64 s;
memcpy(s.u64, szData, sizeof(swap64));
s.u64=ntohll(s.u64);
//Following line is UB in C++, but not in C:
return s.d64;
或没有 UB(代码在 C++ 和 C 中均有效):
unsigned long long u64;
double d64;
//Most compilers will remove the memcpy calls and replace them by simpler instructions
memcpy(&u64, szData, sizeof(u64));
u64=ntohll(u64);
memcpy(&d64, &u64, sizeof(u64));
return d64;