zdi*_*ion 5 c undefined-behavior language-lawyer
对两个不相关的指针(即不指向同一数组或对象的两个指针)执行算术比较是 C 中未定义的行为。
\nint a, b;\nbool ub = &a < &b;\nRun Code Online (Sandbox Code Playgroud)\n然而,人们可以将它们投射到uintptr_t:
int a, b;\nbool not_ub = (uintptr_t)&a < (uintptr_t)&b;\nRun Code Online (Sandbox Code Playgroud)\n演员表已定义,比较也已定义。
\n但是,使用 比较两个指针是否是UB memcmp?
int a, b;\nint* pa = &a;\nint* pb = &b;\nint maybe_ub = memcmp(&pa, &pb, sizeof(int*));\nRun Code Online (Sandbox Code Playgroud)\nC11 \xc2\xa77.24.4.1 说:
\n\n\nmemcmp 函数将 s1 指向的对象的前 n 个字符与 s2 指向的对象的前 n 个字符进行比较。
\n
我对该摘录的理解是比较的是指针的表示,而不是指针本身。因此,我希望调用不会memcmp表现出任何未定义的行为。
由于标准没有指定对象如何存储或表示(特定情况除外,但不是这里),我对结果不感兴趣memcmp不感兴趣,而只是关心它是否是 UB。
Eri*_*hil 10
的行为memcmp(&pa, &pb, sizeof(int*))不是未定义的。我们看到这一点是因为它是由您引用的文本 C 2018 7.24.4 2 定义的:
\n\n该函数将指向的对象的
\nmemcmp第一个字符与指向的对象的第一个字符进行比较ns1ns2字符进行比较。
对象pa和pb由字节组成,根据 C 2018 6.2.6.1 2:
\n\n除了位字段之外,对象由一个或多个字节的连续序列组成,其数量、顺序和编码要么是显式指定的,要么是实现定义的。
\n
sizeof (int *)根据 C 2018 6.5.3.4 2,它们有字节:
\n\n该
\nsizeof运算符产生其操作数\xe2\x80\xa6 的大小(以字节为单位)
如果memcmp表示字节相同,pa并且pb必然具有相同的值,因为字节代表值。如果memcmp指示字节不同,则 C 标准允许 和pa具有pb不同的值或具有相同的值(因为一个值可能具有不同字节的多种表示形式)。
(在当今最常见的 C 实现中,使用平面地址空间,并且指针中的位直接对应于硬件地址。但是,可能并非指针中的所有位都用于该地址。系统可能会使用用户空间进程中的地址只有 48 位,因此 C 实现中的 64 位指针可能有 16 个备用位。这些备用位中的不同值可能并不表示不同的地址。它们可以用于其他目的,或者只是被忽略编译器并允许 \xe2\x80\x9cfloat.\xe2\x80\x9d)
\n