【问题标题】:What, exactly, is memcmp supposed to return?memcmp 到底应该返回什么?
【发布时间】:2017-12-12 00:11:09
【问题描述】:

我想知道函数memcmp 必须返回什么。

我一直在互联网上搜索,通常,memcmp 的定义如下所示:

memcmp() 函数返回一个大于、等于或小于零的整数,因此 s1 指向的对象大于、等于或小于 s2 指向的对象。

从来没有明确说明返回的是什么,究竟:是两个字节值之间的差异,还是 -1、0 或 1?我很困惑:

  • 在小程序中测试函数 memcmp 时,它返回 -1、0 或 1,即使评估的两个字节之间的差值大于 1 或小于 -1。
  • 在 Internet 上查看名为 memcmp 的函数时,它们几乎都以 int 形式返回 2 个字节之间的差异,而不是返回 -1、0 或 1。

由于我无法对函数memcmp 进行足够精确的定义,所以我在这里提出这个问题:函数memcmp 究竟应该返回什么?某处是否有“官方”源代码? (我看过很多memcmp 的源代码,但没有一个给我答案:然后我假设它们不是库 string.h 中编写的函数,至少不是在我的计算机上......)

【问题讨论】:

  • 如果没有指定 - 它是实现定义的。保证行为在您的报价中。
  • 您的报价说明了一切。除此之外的任何内容都是特定于实现的。
  • 是的,它从来没有准确地说明过,因为除了您引用的一般保证之外,实际上没有确切的答案。不,没有“官方”的源代码可供阅读,因为没有官方的 C 标准库,只有流行程度不同的实现。而且因为这种行为是实现定义的,所以他们的源代码不会规定无论如何“必须”发生什么;他们所要做的就是标准所说的,仅此而已。您需要内化标准记录的不同类型的行为,以便进一步阅读任何 C 文档!
  • 唯一保证行为是< 0> 0== 0;针对-11 等特定值进行测试只会以胃灼热告终。
  • @PeterJ:你如何编写(便携式 C)代码,性能优于 memcmp()?要比较相等性,您必须检查所有字节是否相同(尽管如果两个字节数组都足够对齐且足够大,则可以通过比较比字节更大的单位来加快速度)。如果您需要一个速度恒定的解决方案,它必须扫描所有两个内存块,而不是在第一个差异上停下来,否则它可以这样做。

标签: c language-lawyer standard-library memcmp


【解决方案1】:

标准未指定memcmp() 返回的特定值。 C11 标准草案确实在§7.24.4 1 中说:

比较函数返回的非零值的符号 memcmp、strcmp 和 strncmp 由 第一对字符的值之间的差异(两者 解释为 unsigned char) 的对象不同 比较。

因此,只有来自比较函数的非零返回值的符号才应该被视为有意义。此处给出的范围允许每个实现在其认为合适的时候解释这些要求。

另外,请注意没有“官方源代码”;标准是 C 实现必须遵守的文档。即使阅读您正在使用的实现的源代码来查找用于生成memcmp() 返回值的底层方法,在代码中使用这些值充其量是不可移植的,并且容易受到该实现的未来更改的影响。

【讨论】:

    【解决方案2】:

    没有具体说明结果的原因是

    首先,确切的结果并不重要。调用者只需要知道<=> 三个结果之一。定义的行为有效。现在规范可以说返回 -1、0 或 1。那么为什么不说这很重要。见第二点

    第二。通过不指定确切的结果,实现者可以编写非常有效的代码。 memcmp 可以通过计数位或做一些聪明的和来实现。要么。 xor 等不会自然产生 1 或 -1。所以规范对确切的返回值保持沉默。

    【讨论】:

      【解决方案3】:

      它没有指定返回什么整数,它指定结果可以和0比较。

      如果实现完成此测试,则实现返回的任何值都是正确的。

      【讨论】:

        【解决方案4】:

        正如@EugeneSh 所说,它没有定义。 POSIX specification 说,除了你引用的部分:

        非零返回值的符号应由被比较对象中不同的第一对字节(均解释为类型无符号字符)的值之间的差异符号确定。

        因此,只有零/非零和正/负是适用于来自memcmp 的返回值的有意义的测试。不要依赖实际值,因为它们可能在不同的 C 库(甚至可能是处理器架构)之间有所不同。

        源示例

        我在 GitHub 上找到了 GNU C 库 (glibc) 的镜像。 source for memcmp 取两个字节之间的差值(第 332 行),因此返回值一般不会只有 -1 或 +1。然而,一个特定的库可以实现memcmp,但对目标平台最有意义。

        【讨论】:

        • 我不确定为什么提到 POSIX,但它只是解释了标准所说的内容。
        • 查看 GNU C 库的代码时,重要的是要知道顶级目录中的每个源文件(如 string/memcmp.c)只是 默认的某些功能的版本;它们都可以被sysdeps 目录中特定于体系结构或操作系统的代码所取代。尤其是字符串函数,通常会替换为针对特定 CPU 的手动优化汇编版本(例如 sysdeps/x86_64/memcmp.S)。
        • @zwol——这是一个非常有趣的观点,而我并没有意识到这一点。我刚刚在我的答案中添加了 cmets,大意是阅读实际来源和使用发现可能容易受到图书馆未来变化的影响;但您认为这在今天甚至可能无效,是吗?
        • @DavidBowling 是的,我的意思是,例如,memcmp("a", "z", 1) 可能会根据实际使用的 memcmp 实现返回不同的负值。它甚至可以在运行时发生变化 - 获取相同的二进制文件并在具有不同向量指令集的机器上运行它,库将选择不同的内部循环。
        猜你喜欢
        • 1970-01-01
        • 2019-04-28
        • 2014-06-30
        • 2019-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多