据我了解,GCC支持C ++中的所有C99功能。但是如何在C ++代码中处理C99严格别名?
我知道在不相关的类型之间使用C转换进行转换不是严格别名安全的,并且可能生成错误的代码,但是C ++呢?由于严格别名不是C ++标准的一部分(这是正确的吗?),GCC必须自己指定语义。
我在相关类型之间投射const_cast
和static_cast
,因此它们是安全的,而reinterpret_cast
可以打破严格的别名规则。
这是正确的理解吗?
答案 0 :(得分:31)
不,你可能会混合不同的东西。
严格的别名规则与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
限定词。这与别名直接相关,但它本身并不是所谓的严格别名。
答案 1 :(得分:4)
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
答案 2 :(得分:2)
Cpp的概念是一样的;因为您可以使用C样式转换来指导您完成严格别名的安全性。
简而言之:不,使用Cpp铸造(您已经概述过)的方法不能安全地涵盖所有情况。打破规则的一种常见方法是使用static_cast来转换指针。
只需打开编译器警告 - 它会(或应该)告诉你什么是不安全的。