What are the common undefined/unspecified behavior for C that you run into?
C语言中未指定行为的一个示例是对函数自变量的求值顺序。 您可能不知道它可能是从左到右或从右到左。 这将影响 还有哪些其他未指定的行为可以使无意识的程序员感到惊讶? 语言律师的问题。嗯 我的个人top3: 违反严格的别名规则 :-) 编辑这是一个小示例,它两次出错: (假设32位整数和小尾数)
该代码试图通过在浮点数表示中直接与符号位进行位旋转来获取浮点数的绝对值。 但是,通过从一种类型转换为另一种类型来创建指向对象的指针的结果不是有效的C。编译器可能会假定指向不同类型的指针没有指向同一块内存。这对于除void *和char *之外的所有类型的指针都是正确的(符号无关紧要)。 在上面的例子中,我做了两次。一次获取float的整数别名,一次将值转换回float。 有三种有效的方法可以做到这一点。 在转换过程中使用char或void指针。这些总是别名,所以它们是安全的。
使用内存复制。 Memcpy使用void指针,因此也会强制使用别名。
第三种有效方式:使用联合。自C99以来,这显然不是未定义的:
我个人最喜欢的未定义行为是,如果非空源文件未以换行符结尾,则行为未定义。 我怀疑这是真的,尽管除了发出警告之外,没有其他编译器会根据是否以换行符终止对源文件进行不同的处理。因此,除了可能使警告感到惊讶之外,没有什么会让真正的程序员感到惊讶。 因此,对于真正的可移植性问题(主要是依赖于实现的,而不是未指定或未定义的,但我认为这属于问题的实质):
真正严重的行为,即使在您开发的平台上也可能令人惊讶,因为行为只是部分未定义/未指定:
而且,正如我认为Nils提到的那样:
用指向某物的指针划分某物。只是由于某种原因不会编译... :-)
我最喜欢的是:
为了回答一些意见,根据标准,它是未定义的行为。看到这一点,编译器就可以做任何事情,包括格式化硬盘。
例如,如果在上一行之前有
因此我们之后应该看到x == 2。但是,实际上这不是真的,您会发现某些编译器之后的x == 1,甚至x ==3。您必须仔细查看生成的程序集,以了解可能的原因,但是存在差异潜在的问题。本质上,我认为这是因为允许编译器以它喜欢的任何顺序评估两个赋值语句,因此可以先执行 我遇到的另一个问题(已定义,但绝对是意外的)。 炭是邪恶的。
我无法计算已更正printf格式说明符以匹配其参数的次数。任何不匹配都是未定义的行为。
如果函数原型不可用,则编译器不必告诉您您正在使用错误的参数数量/错误的参数类型来调用函数。 我已经看到许多相对缺乏经验的程序员被多字符常量所咬住。 这个:
是字符串文字(其类型为 这个:
是一个普通字符常量(出于历史原因,其类型为 这个:
也是一个完全合法的字符常量,但是其值(仍为 lang的开发人员前不久发布了一些很棒的示例,每个C程序员都应该阅读该示例。一些以前没有提到的有趣的东西:
EE在这里刚刚发现a >>-2有点烦人。 我点点头,告诉他们那是不自然的。 使用变量之前,请务必始终对其进行初始化!当我刚开始使用C时,这使我头痛不已。 |