语言律师问题。嗯凯。
我个人的top3:
-
违反严格的别名规则
-
违反严格的别名规则
-
违反严格的别名规则
:-)
Edit这是一个犯了两次错误的小例子:
(假设 32 位整数和小端)
float funky_float_abs (float a)
{
unsigned int temp = *(unsigned int *)&a;
temp &= 0x7fffffff;
return *(float *)&temp;
}
该代码尝试通过直接在浮点数表示中对符号位进行位调整来获取浮点数的绝对值。
但是,通过从一种类型转换为另一种类型来创建指向对象的指针的结果不是有效的 C。编译器可能会假设指向不同类型的指针不指向同一内存块。对于除 void* 和 char* 之外的所有类型的指针都是如此(符号性并不重要)。
在上面的例子中,我这样做了两次。一次为 float a 获取 int 别名,一次将值转换回 float。
有三种有效的方法可以做到这一点。
在转换期间使用 char 或 void 指针。它们总是别名任何东西,所以它们是安全的。
float funky_float_abs (float a)
{
float temp_float = a;
// valid, because it's a char pointer. These are special.
unsigned char * temp = (unsigned char *)&temp_float;
temp[3] &= 0x7f;
return temp_float;
}
使用内存复制。 Memcpy 采用 void 指针,因此它也会强制使用别名。
float funky_float_abs (float a)
{
int i;
float result;
memcpy (&i, &a, sizeof (int));
i &= 0x7fffffff;
memcpy (&result, &i, sizeof (int));
return result;
}
第三种有效方法:使用联合体。这是明确的自 C99 起不再未定义:
float funky_float_abs (float a)
{
union
{
unsigned int i;
float f;
} cast_helper;
cast_helper.f = a;
cast_helper.i &= 0x7fffffff;
return cast_helper.f;
}