C++ Float64位问题fir解引用类型双关指针将打破严格的别名规则[-Wstrict aliasing]
我正在尝试下面的代码以获得C++ Float64位问题fir解引用类型双关指针将打破严格的别名规则[-Wstrict aliasing],c++,gcc,casting,compiler-optimization,strict-aliasing,C++,Gcc,Casting,Compiler Optimization,Strict Aliasing,我正在尝试下面的代码以获得Float64位值的32位部分的较低和较高值 #define LSL_HI(x) *(1+(sInt32*)&x) #define LSL_LO(x) *(sInt32*)&x [-Wstrict aliasing]选项是-O2优化的一部分,我不必禁用它 解决此问题的解决方案是什么 我从GCC数学库本身获取的这个宏。如果需要浮点64的文字字节,可以执行以下操作: #include <cstdint> static_assert(doubl
Float64
位值的32位部分的较低和较高值
#define LSL_HI(x) *(1+(sInt32*)&x)
#define LSL_LO(x) *(sInt32*)&x
[-Wstrict aliasing]
选项是-O2
优化的一部分,我不必禁用它
解决此问题的解决方案是什么
我从GCC数学库本身获取的这个宏。如果需要浮点64的文字字节,可以执行以下操作:
#include <cstdint>
static_assert(double == 8, "non 64-bit double!");
int
main()
{
double x = 1111.2222;
uint32_t lo = static_cast<uint32_t>(reinterpret_cast<uint64_t>(x) & 0x00000000FFFFFFFF);
uint32_t hi = static_cast<uint32_t>((reinterpret_cast<uint64_t>(x) & 0xFFFFFFFF00000000) >> (8*4));
return 0;
}
#包括
静态_断言(double==8,“非64位double!”);
int
main()
{
双x=1111.2222;
uint32\u t lo=静态转换(重新解释转换(x)和0x00000000FFFFFF);
uint32\u t hi=静态强制转换((重新解释强制转换(x)和0xFFFFFF00000000)>>(8*4));
返回0;
}
我不认为这是你想要做的。如果你想要双倍的小数部分和整个部分,你需要尝试其他的东西。我不确定你想要完成什么,就像迪伦提到的一样 如果您想拆分一个双精度(假设是IEEE 754双精度),您可以这样做(我使用的是ANSI转义序列,这可能不适合您的环境)。我有“拆分为十六进制字节”和“拆分为符号/指数/分数”:
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用std::cout;
使用std::fp进行分类;
使用std::memcpy;
使用std::nan;
使用std::数值_限制;
使用std::reverse;
使用std::setw;
使用std::size\u t;
使用std::string;
使用std::stringstream;
使用std::uint32\t;
使用std::uint64\t;
名称空间{
uint32低32自(双d){
char const*p=重新解释铸件(&d);
uint32_t结果;
memcpy(&result,p,sizeof result);
返回结果;
}
uint32_t高32_自(双d){
char const*p=重新解释铸件(&d);
p+=4;
uint32_t结果;
memcpy(&result,p,sizeof result);
返回结果;
}
字符串hextstr(uint32\u t值){
字符十六进制[]=“0123456789ABCDEF”;
无符号字符缓冲区[4];
memcpy(缓冲区、值、缓冲区大小);
自动p=&缓冲区[0];
细流ss;
char const*sep=“”;
用于(大小i=0;i ss 4)&0xF]标准委员会称之为“流行扩展”[参见基本原理第11页],能够投射指针并使用新投射的指针“以环境的记录方式”执行类型双关语。该标准有意避免要求即使是不适用于低级编程任务的编译器(如将64位浮点值直接分解为32位块)必须支持它,但它允许编译器根据客户的需求或编译器编写者认为合适的任何其他标准支持或不支持此类构造,并且允许在仅寻求“一致性”而非“严格一致性”的程序中的程序中使用此类构造
真正致力于最大限度地适合低级编程任务的实现将通过“以环境特有的文档化方式”处理此类结构来支持该扩展.GCC发出警告,因为未将其配置为适合此类使用;添加编译标志-fno strict aliasing
将正确配置它,从而消除警告
虽然为低级编程设计的编译器不能保证所有可能涉及类型双关的情况都将以对象表示所暗示的方式进行处理,但它们应该可以毫无困难地支持这样的情况:为了访问对象,强制转换指针并立即将其作为新类型取消引用原始类型的对象。但是,不寻求最大限度地适合低级编程的实现可能需要使用笨重的结构,这取决于目标平台,可能需要也可能不需要有效地处理。在没有-fno strict aliasing
标志的情况下调用时,clang和g的优化器cc属于后一类
作为一般原则,假设程序不会执行X的优化在不需要执行X的情况下可能会很有用,但对于最适合使用X来描述其用途的代码来说,可能会适得其反。如果程序能够从使用低级类型双关结构中获益,请记录它只适合与compi一起使用支持它们的ler配置比试图绕过它们的缺失要好,特别是考虑到clang和gcc在试图绕过它们缺乏低级编程支持时可能出现的困境中无法可靠地维护标准。此建议的工作原理与宏“定义LSL_LO(x)(sInt32)&x”的工作原理类似但这无助于消除由于[-Wstrict别名]而产生的警告。我在此次更新中仍然收到相同的警告。该代码或原始代码在以适合低级编程的方式配置的实现上都可以正常工作。在配置为不尝试以适合此目的的方式处理代码的实现上,两者都不应被视为可靠的.Code当然依赖于endian。发布的代码还应给出错误,&
不能应用于右值(浮动文字)
#include <cstdint>
static_assert(double == 8, "non 64-bit double!");
int
main()
{
double x = 1111.2222;
uint32_t lo = static_cast<uint32_t>(reinterpret_cast<uint64_t>(x) & 0x00000000FFFFFFFF);
uint32_t hi = static_cast<uint32_t>((reinterpret_cast<uint64_t>(x) & 0xFFFFFFFF00000000) >> (8*4));
return 0;
}
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
using std::cout;
using std::fpclassify;
using std::memcpy;
using std::nan;
using std::numeric_limits;
using std::reverse;
using std::setw;
using std::size_t;
using std::string;
using std::stringstream;
using std::uint32_t;
using std::uint64_t;
namespace {
uint32_t low32_from(double d) {
char const* p = reinterpret_cast<char const*>(&d);
uint32_t result;
memcpy(&result, p, sizeof result);
return result;
}
uint32_t high32_from(double d) {
char const* p = reinterpret_cast<char const*>(&d);
p += 4;
uint32_t result;
memcpy(&result, p, sizeof result);
return result;
}
string hexstr(uint32_t value) {
char hex[] = "0123456789ABCDEF";
unsigned char buffer[4];
memcpy(buffer, &value, sizeof buffer);
auto p = &buffer[0];
stringstream ss;
char const* sep = "";
for (size_t i = 0; i < sizeof buffer; ++i) {
ss << sep << hex[(*p >> 4) & 0xF] << hex[*p & 0xF];
sep = " ";
++p;
}
return ss.str();
}
string bits(uint64_t v, size_t len) {
string s;
int group = 0;
while (len--) {
if (group == 4) { s.push_back('\''); group = 0; }
s.push_back(v & 1 ? '1' : '0');
v >>= 1;
++group;
}
reverse(s.begin(), s.end());
return s;
}
string doublebits(double d) {
auto dx = fpclassify(d);
unsigned char buffer[8];
memcpy(buffer, &d, sizeof buffer);
stringstream ss;
uint64_t s = (buffer[7] >> 7) & 0x1;
uint64_t e = ((buffer[7] & 0x7FU) << 4) | ((buffer[6] >> 4) & 0xFU);
uint64_t f = buffer[6] & 0xFU;
f = (f << 8) + (buffer[5] & 0xFFU);
f = (f << 8) + (buffer[4] & 0xFFU);
f = (f << 8) + (buffer[3] & 0xFFU);
f = (f << 8) + (buffer[2] & 0xFFU);
f = (f << 8) + (buffer[1] & 0xFFU);
f = (f << 8) + (buffer[0] & 0xFFU);
ss << "sign:\033[0;32m" << bits(s, 1) << "\033[0m ";
if (s) ss << "(-) ";
else ss << "(+) ";
ss << "exp:\033[0;33m" << bits(e, 11) << "\033[0m ";
ss << "(" << setw(5) << (static_cast<int>(e) - 1023) << ") ";
ss << "frac:";
// 'i' for implied 1 bit, '.' for not applicable (so things align correctly).
if (dx == FP_NORMAL) ss << "\033[0;34mi";
else ss << "\033[0;37m.\033[34m";
ss << bits(f, 52) << "\033[0m";
if (dx == FP_INFINITE) ss << " \033[35mInfinite\033[0m";
else if (dx == FP_NAN) ss << " \033[35mNot-A-Number\033[0m";
else if (dx == FP_NORMAL) ss << " \033[35mNormal\033[0m";
else if (dx == FP_SUBNORMAL) ss << " \033[35mDenormalized\033[0m";
else if (dx == FP_ZERO) ss << " \033[35mZero\033[0m";
ss << " " << d;
return ss.str();
}
} // anon
int main() {
auto lo = low32_from(1111.2222);
auto hi = high32_from(1111.2222);
cout << hexstr(lo) << "\n";
cout << hexstr(hi) << "\n";
cout << doublebits(1111.2222) << "\n";
cout << doublebits(1.0) << "\n";
cout << doublebits(-1.0) << "\n";
cout << doublebits(+0.0) << "\n";
cout << doublebits(-0.0) << "\n";
cout << doublebits(numeric_limits<double>::infinity()) << "\n";
cout << doublebits(-numeric_limits<double>::infinity()) << "\n";
cout << doublebits(nan("")) << "\n";
double x = 1.0;
while (x > 0.0) {
cout << doublebits(x) << "\n";
x = x / 2.0;
}
}