据我了解,GCC 在 C++ 中支持其所有 C99 功能。但是在 C++ 代码中如何处理 C99 严格别名呢?
我知道在不相关类型之间使用 C 进行强制转换不是严格混叠安全的,并且可能会生成不正确的代码,但是 C++ 呢?由于严格别名不是 C++ 标准的一部分(对吗?),GCC 必须自己指定语义。
我在相关类型之间进行计算const_cast
和static_cast
转换,因此它们是安全的,同时reinterpret_cast
可以打破严格的别名规则。
这是一个正确的理解吗?
据我了解,GCC 在 C++ 中支持其所有 C99 功能。但是在 C++ 代码中如何处理 C99 严格别名呢?
我知道在不相关类型之间使用 C 进行强制转换不是严格混叠安全的,并且可能会生成不正确的代码,但是 C++ 呢?由于严格别名不是 C++ 标准的一部分(对吗?),GCC 必须自己指定语义。
我在相关类型之间进行计算const_cast
和static_cast
转换,因此它们是安全的,同时reinterpret_cast
可以打破严格的别名规则。
这是一个正确的理解吗?
不,您可能正在混合不同的东西。
严格的别名规则与 C99 标准完全无关。严格的别名规则植根于自 [标准化] 时代开始以来存在于 C 和 C++ 中的部分标准。禁止通过另一种类型的左值访问一种类型的对象的子句存在于 C89/90(6.3)和 C++98(3.10/15 )中)。这就是严格别名的全部意义,不多也不少。只是并非所有编译器都想要(或敢于)强制执行或依赖它。C 和 C++ 语言有时都被用作“高级汇编”语言,严格的别名规则经常会干扰这种使用。正是 GCC 做出了这一大胆的举动,并决定开始在优化中依赖严格的别名规则,这经常会引起那些“汇编”类型的抱怨。
确实,打破 C++ 中严格的别名规则的最直接的方法是reinterpret_cast
(当然还有 C 风格的强制转换)。但是,static_cast
也可以用于该目的,因为它允许通过void *
在“链式”强制转换中用作中间类型来打破严格的别名
int *pi;
...
double *pd = static_cast<double *>(static_cast<void *>(pi));
const_cast
不能在兼容的编译器中破坏严格的别名。
至于 C99……C99 引入的是restrict
限定符。这与别名直接相关,但它本身并不是所谓的严格别名。
static_cast
也可以打破别名规则,因为编译器信任您确保目标类型与对象的实际运行时类型相关。考虑:
extern void f(double*, int*); // compiler may optimize assuming that arguments don't overlap
double d;
void* pv = &d;
int* pi = static_cast<int*>(pv);
f(&d, pi); // assumption is violated
Cpp中的概念是一样的;因为您可以使用 C 样式转换来指导您完成被认为是安全的严格别名。
简而言之:不,使用 Cpp 转换的方法(您已概述)不会安全地涵盖所有情况。打破规则的一种常见方法是使用 static_cast 来转换指针。
只需打开编译器警告——它会(或者,应该)告诉你什么是不安全的。