类型双关语和别名是不同但相关的概念,一些编译器编写者似乎无法区分它们,尽管它们在很大程度上是正交的。
类型双关是指将存储作为一种类型写入并作为另一种类型读取的情况,通常是为了允许将值解释为位序列,允许将位序列解释为值,或允许将值用作表示匹配的另一种类型,至少在感兴趣的部分中。例如,后一种形式的类型双关语可能在以下情况下很有用:一个人可能有指向各种结构类型的指针,所有这些结构类型都共享一个公共初始序列,并且可能需要对所有的公共初始序列成员进行操作。尽管结构的类型不同,但这些结构。请注意,即使标准包含明确的保证,表明后一种形式的类型双关应该是有用的,但将其与别名混淆的编译器不支持这种结构。
别名是指一个不同的概念,其中使用两个或多个同时活动但看似不相关的手段以相互交互的方式访问存储。给定类似的东西:
int test1(int *p1, int *p2)
{
*p1 = 1;
*p2 = 2;
return *p1;
}
如果p1==p2,则p1 和p2 将使用别名,因为p1 将用于访问p2 标识的存储空间,介于p2 的创建和最后一次使用之间,在以下上下文中p1 不能从 p2 创建 [有可能 p1 在调用函数之前可能已经从 p2 创建,但不可能在函数内从 p2 派生 p1 ]。因为标准允许标识相同类型的左值之间存在别名,但是,上述构造将定义当p1==p2 时的行为,尽管事实上p1 和p2 有别名。
另一方面,假设如下:
struct s1 {int x; };
struct s2 {int x; };
union s1s2 {struct s1 v1; struct s2 v2; } uarr[100];
int test1(int i, int j)
{
int temp;
{ struct s1 *p1 = &uarr[i].v1; temp = p1->x; }
if (temp)
{ struct s2 *p2 = &uarr[j].v2; p2->x = 1; }
{ struct s1 *p3 = &uarr[i].v1; temp = p3->x; }
return temp;
}
在这里,指针p1、p2 和p3 具有明显不相交的生命周期,因此不会同时处于活动状态并相互别名。每个指针都独立派生自uarr,每个指针的生命周期将在下次使用uarr 之前结束。因此,此代码使用类型双关语来访问与struct s1 和struct s2 相同的存储,但正如所写的那样,并没有利用别名,因为对所讨论存储的所有访问显然都来自同一个根-级别对象uarr。
不幸的是,尽管基于类型的访问规则旨在(根据基本原理和脚注)指示事物何时允许别名,但一些编译器以使语言特性的方式解释它们例如 Common Initial Sequence 保证基本上是无用的,因为他们使用类型访问规则作为重写代码的借口,以删除从uarr 派生的p3,从而在已经存在的地方引入了别名没有。