特别是,以下是明确定义的,还是表现出未定义的行为?
memcmp(0, 0, 0);
这在 C 和 C++ 之间有区别吗?理想情况下,请提供标准的报价。
特别是,以下是明确定义的,还是表现出未定义的行为?
它是未定义的。C99 7.21.1/2 介绍了所有字符串函数:
除非在本小节中对特定函数的描述中另有明确说明,否则此类调用上的指针参数仍应具有有效值
并且memcmp
7.21.4.1 中的描述没有明确说明。
这在 C 和 C++ 之间有区别吗?
不,C++ 遵从 C 对 C 库函数的定义,并且对memcmp
.
令人惊讶的是,尽管这似乎是标准中一个明显错误的案例——它忽略了零长度的 memcmp 很好(并且总是返回 0)——建立了大量的理论来解释为什么应该将其标记为“未定义的行为”。上面接受的答案就是一个很好的例子,后面的讨论也是如此。
可悲的是,在memcmp(0,0,0)
未定义的理论站稳脚跟之后,Gcc 决定通过向 memcmp 添加一个 __nonull 属性来强烈执行这个不幸的决定,从而导致可能错误的优化和 UBSAN 警告。只有在那个时候,这个调用才真正变得未定义:-(
但是如果我们从逻辑上看它,它memcmp(0, 0, 0)
是定义明确的,并且应该总是返回 0(相等):Posixmemcmp()
中将 的功能描述为:
memcmp() 函数应将 s1 指向的对象的前 n 个字节(每个都解释为无符号字符)与 s2 指向的对象的前 n 个字节进行比较。
当 n=0 时,这意味着不会比较任何字节。如果没有比较字节,则不应取消引用任何指针,并且该指针是什么都没有关系。这应该是显而易见的,而 C 标准忘记提及它的事实只不过是标准中的一个错误。
有趣的是,Linux memcmp(3)和FreeBSD memcmp(3)手册页不同意 gcc,并声称应该允许这种情况:
Linux手册页说:
如果 n 为零,则返回值为零。
虽然 BSD 说:
零长度字符串总是相同的。