相关疑难解决方法(0)

什么是将一个浮点数类型化为int的正确方法,反之亦然?

下面的代码通过一些位攻击执行快速反平方根操作.该算法可能是由Silicon Graphics在1990年代早期开发的,它也出现在Quake 3中. 更多信息

但是我从GCC C++编译器收到以下警告:解除引用类型惩罚指针将破坏严格别名规则

我应该使用static_cast,reinterpret_cast还是dynamic_cast在这种情况下使用?

float InverseSquareRoot(float x)
{
    float xhalf = 0.5f*x;
    int32_t i = *(int32_t*)&x;
    i = 0x5f3759df - (i>>1);
    x = *(float*)&i;
    x = x*(1.5f - xhalf*x*x);
    return x;
}
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing gcc-warning undefined-behavior type-punning

24
推荐指数
4
解决办法
6830
查看次数

浮点和严格别名

我试图从浮点数中提取位而不调用未定义的行为.这是我的第一次尝试:

unsigned foo(float x)
{
    unsigned* u = (unsigned*)&x;
    return *u;
}
Run Code Online (Sandbox Code Playgroud)

据我了解,由于严格的别名规则,这不能保证工作,对吧?如果使用字符指针进行中间步骤,它是否有效?

unsigned bar(float x)
{
    char* c = (char*)&x;
    unsigned* u = (unsigned*)c;
    return *u;
}
Run Code Online (Sandbox Code Playgroud)

或者我是否必须自己提取单个字节?

unsigned baz(float x)
{
    unsigned char* c = (unsigned char*)&x;
    return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}
Run Code Online (Sandbox Code Playgroud)

当然,这有一个缺点,取决于字节顺序,但我可以忍受.

工会黑客肯定是未定义的行为,对吧?

unsigned uni(float x)
{
    union { float f; unsigned u; };
    f = x;
    return u;
}
Run Code Online (Sandbox Code Playgroud)

为了完整起见,这里有一个参考版本foo.也是未定义的行为,对吗?

unsigned ref(float x)
{ …
Run Code Online (Sandbox Code Playgroud)

c++ floating-point bits strict-aliasing type-punning

22
推荐指数
3
解决办法
2460
查看次数

将double数组转换为double的结构

将双数组转换为由双精度构成的结构是否可以?

struct A
{
   double x;
   double y;
   double z;
};

int main (int argc , char ** argv)
{
   double arr[3] = {1.0,2.0,3.0};
   A* a = static_cast<A*>(static_cast<void*>(arr));
   std::cout << a->x << " " << a->y << " " << a->z << "\n";
}
Run Code Online (Sandbox Code Playgroud)

这打印1 2 3.但它是否保证每次都可以与任何编译器一起工作?

编辑:根据

9.2.21:指向标准布局结构对象的指针,适当转换?使用reinterpret_cast,指向其初始成员(...),反之亦然.

如果我用我的代码替换

struct A
{
  double & x() { return data[0]; }
  double & y() { return data[1]; }
  double & z() { return data[2]; }
private:
   double data[3];
}; …
Run Code Online (Sandbox Code Playgroud)

c++ arrays struct static-cast language-lawyer

10
推荐指数
2
解决办法
840
查看次数

reinterpret_cast会导致未定义的行为吗?

我有一个类模板A,其中包含一个指针容器(T*):

template <typename T>
class A {
public:
   // ... 
private:
   std::vector<T*> data;
};
Run Code Online (Sandbox Code Playgroud)

和一堆功能,如:

void f(const A<const T>&);
void g(const A<const T>&);
Run Code Online (Sandbox Code Playgroud)

是否可以将呼叫通过铸造这些功能从A<const T>A<T>

A<double> a;
... 
auto& ac = reinterpret_cast<const A<const double>&>(a);
f(ac);
Run Code Online (Sandbox Code Playgroud)

我很确定这段代码有不确定的行为.

在现实生活中使用这种转换是危险的吗?

c++ templates reinterpret-cast

8
推荐指数
2
解决办法
1876
查看次数

高效的类型双关,没有未定义的行为

假设我正在开发一个名为 libModern 的库。该库使用称为 libLegacy 的遗留 C 库作为实现策略。libLegacy 的界面如下所示:

typedef uint32_t LegacyFlags;

struct LegacyFoo {
    uint32_t x;
    uint32_t y;
    LegacyFlags flags;
    // more data
};

struct LegacyBar {
    LegacyFoo foo;
    float a;
    // more data
};

void legacy_input(LegacyBar const* s); // Does something with s
void legacy_output(LegacyBar* s); // Stores data in s
Run Code Online (Sandbox Code Playgroud)

出于各种原因,libModern 不应该向用户公开 libLegacy 的类型,其中包括:

  • libLegacy 是一个不应泄露的实现细节。libModern 的未来版本可能会选择使用另一个库而不是 libLegacy。
  • libLegacy 使用难以使用、容易误用的类型,这些类型不应成为任何面向用户的 API 的一部分。

处理这种情况的教科书方法是 pimpl 习惯用法:libModern 将提供一个包装类型,该类型内部有一个指向遗留数据的指针。然而,这在这里是不可能的,因为 libModern 无法分配动态内存。一般来说,其目标不是增加大量开销。

因此,libModern 定义了自己的类型,这些类型与遗留类型布局兼容,但具有更好的接口。在此示例中,它使用强标志enum而不是普通uint32_t标志:

enum class ModernFlags : …
Run Code Online (Sandbox Code Playgroud)

c++ gcc language-lawyer type-punning c++20

8
推荐指数
1
解决办法
669
查看次数

按位转换uint32_t以在C/C++中浮动

我从网络接收缓冲区,该缓冲区被转换为32位字的数组.我有一个单词被我的界面文档定义为ieee float.我需要从缓冲区中提取这个单词.在不调用转换的情况下从一种类型转换为另一种类型很困难.这些位已经符合ieee浮点标准,我不想重新排列任何位.

我的第一次尝试是将地址转换uint32_t为a void*,然后将其转换void*为a float*,然后取消引用为float:

float ieee_float(uint32_t f)
{
    return *((float*)((void*)(&f)));
}
Run Code Online (Sandbox Code Playgroud)

错误:解除引用类型惩罚指针将破坏严格别名规则[-Werror = strict-aliasing]

我的第二次尝试是这样的:

float ieee_float(uint32_t f)
{
    union int_float{
        uint32_t i;
        float f;
    } tofloat;

    tofloat.i = f;
    return tofloat.f;
}
Run Code Online (Sandbox Code Playgroud)

然而,街上的一句话是,工会完全不安全.从最近没有编写的联合成员读取它是未定义的行为.

所以我尝试了更多的C++方法:

float ieee_float(uint32_t f)
{
  return *reinterpret_cast<float*>(&f);
}
Run Code Online (Sandbox Code Playgroud)

错误:解除引用类型惩罚指针将破坏严格别名规则[-Werror = strict-aliasing]

我的下一个想法是"搞砸它.为什么我要处理指针呢?" 并尝试过:

float ieee_float(uint32_t f)
{
  return reinterpret_cast<float>(f);
}
Run Code Online (Sandbox Code Playgroud)

错误:从'uint32_t {aka unsigned int}'类型无效转换为'float'类型

有没有办法在不触发警告/错误的情况下进行转换?我用g ++编译-Wall -Werror.我宁愿不接触编译器设置.

我标记了C,因为c解决方案是可以接受的.

c++

4
推荐指数
1
解决办法
1417
查看次数

std::bit_cast 和 std::start_lifetime_as 之间有什么有用的区别吗?

std::bit_cast显然是在 c++20 中引入的。并std::start_lifetime_as建议用于 c++23(来自P0593R5)。由于它们似乎都要求所涉及的数据类型无论如何都是微不足道的,一旦引入后者,是否还需要前者?

对于没有提供有关这些新功能的更多信息,提前致歉。我只是在观看了关于类型双关的 cppcon 2019 讲座后才听说过它们,而且我无法start_lifetime_as通过谷歌找到太多相关信息。我希望看到这个的其他人可能会知道更多。

c++ c++-standard-library type-punning c++20

4
推荐指数
2
解决办法
1260
查看次数

C++中安全高效的Punning类型

uint32_t Seed() {
    uint64_t seed = GetSomeReasonable64BitIntegerSeed();
    return *(uint32_t*)&seed ^ *((uint32_t*)&seed + 1);
}
Run Code Online (Sandbox Code Playgroud)

上面不是真正的代码,但这基本上是真正的代码所做的.我从g ++那里得到一个警告,它违反了严格的别名,谷歌搜索它,好吧我想解决它.我发现了这个问题,但它没有提供一个明确的解决方案,除了使用memcpy或依赖于未定义但实际上没有问题的行为,即访问联合的未设置成员.

我能想到的当前选择是,

  1. 使用memcpy.
  2. 使用a union并将此部分编译为C,其中语言标准允许通过联合进行类型惩罚.

c++ casting type-punning

3
推荐指数
1
解决办法
224
查看次数

Cast raw bytes to any datatype

I'm worried if my implementation is unsafe or could be improved. Suppose I have an array of bytes (more specifically, std::byte); is casting an element's address to a void pointer and then to any datatype safe?

template <typename To>
constexpr To *byte_cast(std::byte &From) {
  return static_cast<To *>(static_cast<void *>(&From));
}

// or rather
template <typename To>
constexpr To *byte_cast(std::byte *From) {
  return static_cast<To *>(static_cast<void *>(From));
}
Run Code Online (Sandbox Code Playgroud)

I'm avoiding reinterpret_cast due to its unreliability. Do note that I want to the …

c++ reinterpret-cast c++17

3
推荐指数
1
解决办法
971
查看次数