15

特别是,以下是明确定义的,还是表现出未定义的行为?

memcmp(0, 0, 0);

这在 C 和 C++ 之间有区别吗?理想情况下,请提供标准的报价。

4

2 回答 2

33

特别是,以下是明确定义的,还是表现出未定义的行为?

它是未定义的。C99 7.21.1/2 介绍了所有字符串函数:

除非在本小节中对特定函数的描述中另有明确说明,否则此类调用上的指针参数仍应具有有效值

并且memcmp7.21.4.1 中的描述没有明确说明。

这在 C 和 C++ 之间有区别吗?

不,C++ 遵从 C 对 C 库函数的定义,并且对memcmp.

于 2013-05-03T15:55:55.693 回答
3

令人惊讶的是,尽管这似乎是标准中一个明显错误的案例——它忽略了零长度的 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 说:

零长度字符串总是相同的。

于 2020-07-07T22:05:31.563 回答