遇到的 C 的常见未定义/未指定行为是什么?

问题描述

语言律师问题。嗯。

我的个人top3:

  1. 违反严格的别名规则

  2. 违反严格的别名规则

  3. 违反严格的别名规则

:-)

这里有一个小例子,它做错了两次:

(假设 32 位整数和小端)

float funky_float_abs (float a)
{
  unsigned int temp = *(unsigned int *)&a;
  temp &= 0x7fffffff;
  return *(float *)&temp;
}

该代码试图通过直接在浮点表示中与符号位进行位旋转来获得浮点的绝对值。

但是,通过从一种类型转换为另一种类型来创建指向对象的指针的结果是无效的 C。编译器可能会假定指向不同类型的指针不指向同一块内存。这适用于除 void 和 char 之外的所有类型的指针(符号无关紧要)。

在上述情况下,我这样做了两次。一次获取浮点 a 的 int-alias,一次将值转换回浮点数。

有三种有效的方法可以做到这一点。

在强制转换期间使用 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;
}

解决方法

C 语言中未指定行为的一个示例是函数参数的求值顺序。它可能是从左到右或从右到左,你只是不知道。这将影响评估方式foo(c++,c)foo(++c,c)评估方式。

还有哪些其他未指明的行为会让不知情的程序员感到惊讶?

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...