2

这很可能以前曾以其他方式被问过(如果不是,我会感到惊讶),但如果是的话,我很难找到它。

鉴于:

#include <iostream>
#include <string>

int main()
{
    int * const pi = new int(1);
    long int * const pl = reinterpret_cast<long int * const>(pi);
    std::cout << "val: " << *pl << std::endl;
    return 0;
}

我收到警告:

<source>: In function 'int main()':
<source>:7:27: warning: type qualifiers ignored on cast result type [-Wignored-qualifiers]
    7 |     long int * const pl = reinterpret_cast<long int * const>(pi);
      |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ASM generation compiler returned: 0
<source>: In function 'int main()':
<source>:7:27: warning: type qualifiers ignored on cast result type [-Wignored-qualifiers]
    7 |     long int * const pl = reinterpret_cast<long int * const>(pi);
      |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Execution build compiler returned: 0
Program returned: 0
val: 1

但我不确定为什么我会收到这个警告,因为重新转换也应该是一个 const 指针——只是指向不同的类型。我想实现相同的代码(如果忽略警告则有效),但没有警告。

4

1 回答 1

10

long int * const是指向可变数据的不可变指针。

reinterpret_cast返回一个临时对象。在大多数临时对象(包括这个)上,顶级类型的不变性是无关紧要的。

这个:

long int * const pl = reinterpret_cast<long int * const>(pi);

是相同的

long int * const pl = reinterpret_cast<long int *>(pi);

编译器正在警告你,因为大概你认为const在那里打字做了什么,你错了,它什么也没做。


现在,这与您所问的内容没有直接关系,但我没有提到这一点是失职的:

std::cout << "val: " << *pl << std::endl;

导致您的程序表现出未定义的行为。指向的对象不是 a long int,它是 a int,并且您正在将其作为不是类型的对象进行访问。

reinterpret_cast不是“将这些字节视为不同的类型”,尽管许多人将其视为原样。在 C++ 标准下,此类操作几乎总是未定义的行为。

将对象 A 的字节解释为类型 B 的对象(当它们是适当的普通类型时)的正确方法是使用类似memcpy.

int * const pi = new int(1);
long int l = 0;
static_assert( sizeof(*pi) == sizeof(l) );
::memcpy( &l, pi, sizeof(l) ); // or l = std::bit_cast<long int>(*pi) in C++20
std::cout << "val: " << l << std::endl;

如果实现定义了输出,这是合法的,因为您可以自由复制足够琐碎类型的字节,并且long int要求没有陷阱值。


在 C++ 中没有合法的方法可以将一块内存作为 along intint. 允许在 C++ 中使用的别名(将一种类型视为另一种类型)的数量是有限的,因为违反别名会使某些非常强大的优化变得不可能或不切实际。

许多程序忽略了这一事实,并在您执行此类操作时依赖编译器生成“幼稚”的程序集。他们正在生成表现出未定义行为的代码。

于 2020-10-07T15:14:41.010 回答