3

我最近一直在阅读有关严格混叠的文章。C/C++ 标准说以下代码是无效的(未定义的行为是正确的),因为编译器可能在a某处缓存了值,并且在我更新时不会识别它需要更新值b

float *a;
...
int *b = reinterpret_cast<int*>(a);
*b = 1;

该标准还说char*可以为任何东西加上别名,因此(如果我错了,请纠正我)编译器会在对char*变量进行写访问时重新加载所有缓存的值。因此,以下代码将是正确的:

float *a;
...
char *b = reinterpret_cast<char*>(a);
*b = 1;

但是在根本不涉及指针的情况下呢?例如,我有以下代码,GCC 会向我抛出关于严格别名的警告。

float a = 2.4;
int32_t b = reinterpret_cast<int&>(a);

我想要做的只是复制原始值a,所以不应该应用严格的别名。这里是否存在可能的问题,或者只是 GCC 对此过于谨慎?

编辑

我知道有一个使用memcpy的解决方案,但它导致代码的可读性要差得多,所以我不想使用那个解决方案。

编辑2

int32_t b = *reinterpret_cast<int*>(&a);也不起作用。

解决了

这似乎是GCC 中的一个错误

4

3 回答 3

3

如果你想复制一些内存,你可以告诉编译器这样做:

编辑:添加了一个功能更易读的代码:

#include <iostream>
using std::cout; using std::endl;
#include <string.h>

template <class T, class U>
T memcpy(const U& source)
{
    T temp;
    memcpy(&temp, &source, sizeof(temp));
    return temp;
}

int main()
{
    float f = 4.2;
    cout << "f: " << f << endl;

    int i = memcpy<int>(f);
    cout << "i: " << i << endl;
}

[代码] [更新代码]

编辑:正如用户/GMan 在评论中正确指出的那样,一个全功能的实现可以检查它T并且UPODs。但是,鉴于函数的名称仍然memcpy是 ,依赖开发人员将其视为与原始memcpy. 这取决于您的组织。此外,使用目标的大小,而不是源的大小。(谢谢,奥利。)

于 2011-02-20T20:27:26.830 回答
1

基本上,严格的别名规则是“使用不同于其声明的类型的其他类型访问内存是未定义的,但字符数组除外”。所以,gcc 并不过分谨慎。

于 2011-02-20T20:28:03.977 回答
0

如果这是您经常需要做的事情,您也可以只使用一个联合,恕我直言,对于这个特定目的,它比强制转换或 memcpy 更具可读性:

union floatIntUnion {
  float a;
  int32_t b;
};

int main() {
  floatIntUnion fiu;
  fiu.a = 2.4;
  int32_t &x = fiu.b;
  cout << x << endl;
}

我意识到这并不能真正回答您关于严格混叠的问题,但我认为这种方法使代码看起来更干净并更好地显示您的意图。

并且还要意识到,即使正确地进行复制,也不能保证int您得到的结果将与float其他平台上的相同,因此如果您打算创建交叉,请计算这些浮点数/整数的任何网络/文件 I/O -平台项目。

于 2011-02-20T20:43:08.663 回答