C++ 将指针从一种类型转换为另一种类型

标签 c++ pointers casting strict-aliasing

我听说不允许将指针从一种类型转换为另一种类型,但我不明白为什么。

例如,在下面的代码中,我所做的只是读取强制转换的值,所以怎么可能出错呢?

struct Foo {
    int a, b, c, d;
};

int main() {
    Foo f = {1, 2, 3, 4};

    int *abcd = *((int *)&f);

    // Now I should be able to access the values like:
    int a = abcd[0];
    int b = abcd[1];
   
    // Then, I only read the values
    // ...

    return 0;
}

最佳答案

C++ 源自 C,C89 标准的作者不想禁止编译器,给出类似 [他们的示例,逐字引用] 的内容:

int a;
void f( double * b )
{
  a = 1;
  *b = 2.0;
  g(a); // Presumably g is declared as e.g. `void g(int);` somewhere?
} 

生成的代码将写入 a 的值传递给 g,而不是在写入 之后读取 a* b 并传递 g 读取的任何值。在对象被访问两次的情况下,这种优化是完全合理的,并且编译器在处理此类访问时需要看到的任何内容都不会暗示对象类型与这些访问之间使用的任何其他类型之间的任何关系。

正如标准的作者认为没有必要强制实现能够处理任何特定的函数调用嵌套一样,他们认为没有必要强制编译器花费任何特定级别的努力来识别不同指针和左值之间的关系类型。给出类似的东西:

long get_float_bits( float * b )
{
  return *(long*)b;
} 
float q;
long test(void)
{
  q = 1.0f;
  long result = get_float_bits(&q);
  q = 2.0f;
}

我认为委员会成员无法想象任何编译器会认真争论因为 get_float_bits 不可能访问类型为 float 的对象,一个高质量的编译器应该省略对 q 的第一次写入。这样的逻辑将被视为类似于编译器编写者的决定,因为标准不要求实现支持超过两层的函数嵌套,所以高质量的编译器应该通过省略对它们可以证明嵌套在的函数的任何调用来优化程序至少四深。标准不禁止此类行为的原因并不是作者想邀请它,而是因为他们认为此类行为显然非常离谱,以至于没有人会购买以这种方式行事的编译器。

不幸的是,C89 的作者特意避免暗示某些实现可能被视为比其他实现更好,因此避免提及质量实现应该做的事情而不是绝对需要做的事情,以及 C89 的作者gcc 将这种规避解释为任何依赖标准未强制要求的任何代码都应被视为“损坏”。

关于C++ 将指针从一种类型转换为另一种类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63587047/

相关文章:

c++ - 如何使用 Halide 分析器

检查字符串是否改变

c - 什么时候使用双指针?

javascript - 解析一个以变量为名称的 json 对象

c# - 泛型与继承 : What am I doing wrong here?

c++ - 放置新和删除

c++ - 使用 ""或 <> 包含 boost 头文件

c++ - 用于将字符串放入整数的 cin 失败标志

c++ - libthrift-0.9.1.so : cannot open shared object file: No such file or directory

types - Dart 中的接口(interface)约束