使用memcmp比较两个不相关的指针是UB吗?

zdi*_*ion 5 c undefined-behavior language-lawyer

对两个不相关的指针(即不指向同一数组或对象的两个指针)执行算术比较是 C 中未定义的行为。

\n
int a, b;\nbool ub = &a < &b;\n
Run Code Online (Sandbox Code Playgroud)\n

然而,人们可以将它们投射到uintptr_t

\n
int a, b;\nbool not_ub = (uintptr_t)&a < (uintptr_t)&b;\n
Run Code Online (Sandbox Code Playgroud)\n

演员表已定义,比较也已定义。

\n

但是,使用 比较两个指针是否是UB memcmp

\n
int a, b;\nint* pa = &a;\nint* pb = &b;\nint maybe_ub = memcmp(&pa, &pb, sizeof(int*));\n
Run Code Online (Sandbox Code Playgroud)\n

C11 \xc2\xa77.24.4.1 说:

\n
\n

memcmp 函数将 s1 指向的对象的前 n 个字符与 s2 指向的对象的前 n 个字符进行比较。

\n
\n

我对该摘录的理解是比较的是指针的表示,而不是指针本身。因此,我希望调用不会memcmp表现出任何未定义的行为。

\n

由于标准没有指定对象如何存储或表示(特定情况除外,但不是这里),我对结果不感兴趣memcmp不感兴趣,而只是关心它是否是 UB。

\n

Eri*_*hil 10

的行为memcmp(&pa, &pb, sizeof(int*))不是未定义的。我们看到这一点是因为它是由您引用的文本 C 2018 7.24.4 2 定义的:

\n
\n

该函数将指向的对象的memcmp第一个字符与指向的对象的第一个字符进行比较ns1ns2字符进行比较。

\n
\n

对象papb由字节组成,根据 C 2018 6.2.6.1 2:

\n
\n

除了位字段之外,对象由一个或多个字节的连续序列组成,其数量、顺序和编码要么是显式指定的,要么是实现定义的。

\n
\n

sizeof (int *)根据 C 2018 6.5.3.4 2,它们有字节:

\n
\n

sizeof运算符产生其操作数\xe2\x80\xa6 的大小(以字节为单位)

\n
\n

如果memcmp表示字节相同,pa并且pb必然具有相同的值,因为字节代表值。如果memcmp指示字节不同,则 C 标准允许 和pa具有pb不同的值或具有相同的值(因为一个值可能具有不同字节的多种表示形式)。

\n

(在当今最常见的 C 实现中,使用平面地址空间,并且指针中的位直接对应于硬件地址。但是,可能并非指针中的所有位都用于该地址。系统可能会使用用户空间进程中的地址只有 48 位,因此 C 实现中的 64 位指针可能有 16 个备用位。这些备用位中的不同值可能并不表示不同的地址。它们可以用于其他目的,或者只是被忽略编译器并允许 \xe2\x80\x9cfloat.\xe2\x80\x9d)

\n

  • @gulpr:这绝对不是未定义的行为。只是一个不确定的结果。 (3认同)
  • @gulpr:给定的 `memcmp(&amp;pa, &amp;pb, sizeof(int*))` 中没有潜在的未定义行为。 (2认同)