我们从char *数组强制转换数据,其功能如下所示:
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字节,无符号long long。 并将双值-1.1512299550195975转换为3.6975400899608046。但是输入和输出应该相等(等于-1.1512299550195975)。这种情况仅在AIX中发生。在其他平台上,我们得到正确的结果。
我们在项目中使用优化级别O2。如果我将优化级别用作O1,那么数据将正确转换。 您能为我提供帮助吗,您如何看待,为什么优化级别O1的转换正确,为什么优化级别O2的转换不正确?可能是我应该在编译中关闭aix还是为aix设置一些标志?谢谢。 Aix编译器版本为13.1.3。
我们从二进制文件中以char数组格式获得了double值。我们从Oracle数据库的事务日志中解析数据。例如,oracle将double值写入为'40 0d 94 8f e6 10 3e 93',我们应该在double类型值中将其转换为'-1,1512299550195975'。但是在唯一的aix中,我们得到了“ 3,6975400899608046”错误的值
答案 0 :(得分:0)
您的实现依赖未定义的行为,尤其是违反了严格别名规则,正如有人评论的那样。
这就是为什么有时它可以工作(没有优化)而有时不起作用的原因。
为避免违反严格别名,您可以使用以下之一:
仅在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;