正在打破严格别名规则的演员

时间:2010-09-21 19:40:37

标签: c++ reinterpret-cast strict-aliasing type-punning

我有一个带有无符号long *的函数,需要将它传递给带有unsigned int *的外部库,并且在这个平台上unsigned int / long的大小相同。

void UpdateVar(unsigned long* var) {
   // this function will change the value at the address of var
   ExternalLibAtomicUpdateVar((unsigned int*)var); // lib atomically updates variable
}

这会产生一个警告,说它违反了严格别名规则。有没有工作?

谢谢

编辑:我为不清楚而道歉。代码是一个原子更新,所以绕过库来存储它不是一个选项。我可以下载到汇编但我想在C ++中这样做。

3 个答案:

答案 0 :(得分:8)

void UpdateVar(unsigned long* var) {
   unsigned int x = static_cast<unsigned int>(*var);
   ExternalLibUpdateVar(&x);
   *var = static_cast<unsigned long>(x);
}

答案 1 :(得分:2)

这应该有效:

void UpdateVar(unsigned long* var) {
   // this function will change the value at the address of var
   ExternalLibUpdateVar(reinterpret_cast<unsigned int*>(var));
}

答案 2 :(得分:1)

C标准中没有规定intlong必须具有相同的尺寸;此外,即使它们确实具有相同的大小,标准中没有任何内容要求它们具有相同的表示形式(除此之外,它们可能具有填充位和陷阱表示的不兼容组合,使得两种类型之间的混叠不能用于任何有用的目的)。

标准的作者不希望强制实施者针对平台,intlong之间的别名无法识别此类别名。他们也不想编写适用于某些平台的规则(别名可用于某些目的的规则),而不是其他平台(那些不会用于其他平台的规则)。相反,他们认为编写高质量编译器的人会尝试在有用的情况下识别别名。

能够使用指向一个32位类型的指针来读取和写入具有相同表示的另一个32位类型的值显然是有用的,特别是如果API被分割为它们期望的类型。如果平台上的某些普通API使用int*表示32位值而其他API使用long*,则该平台的 quality 通用实现必须允许任何一种类型的数据可以使用另一个指针访问。

然而,不幸的是,一些编译器的作者对于快速处理某个程序子集更感兴趣,而不是有效地处理更大的程序子集,如果必要的话,不能依赖它来生成有用的代码。在使用相同数据表示但不同命名类型的API之间交换数据,除非完全禁用别名分析。当然,如果一个人的目标是C语言适合微控制器上的通用用途,那么这些问题并不重要。