【发布时间】:2020-06-14 18:31:11
【问题描述】:
问题:将 2 个指针与灵活的数组成员进行比较是否大于(小于)和相等?
这是struct inotify_event 在 Linux 中的声明方式:
struct inotify_event {
int wd; /* Watch descriptor */
uint32_t mask; /* Mask describing event */
uint32_t cookie; /* Unique cookie associating related
events (for rename(2)) */
uint32_t len; /* Size of name field */
char name[]; /* Optional null-terminated name */
};
为简单起见省略大小检查,让我们考虑以下代码:
int inotify_fd = inotify_init();
//...
struct inotify_event *ino_buf = malloc(sizeof(inotify_event) * 4096);
read(inotify_fd, ino_buf, sizeof(inotify_event) * 4096));
struct inotify_event *first_event = ino_buf;
struct inotify_event *second_event =
((char *) ino_buf) + sizeof(struct inotify_event) + first_event->len;
if(first_event < second_event){ //UB?
//...
}
我认为指向包含灵活数组成员的结构的指针的比较始终是 UB(即使它们相同)
N2346/6.7.2.1p3(我的雇员):
具有多个命名成员的结构的最后一个成员可以 数组类型不完整;这样的结构(以及任何工会 可能递归地包含这样一个结构的成员) 不应是结构的成员或数组的元素。
OTOH,N2346/6.5.8p5 需要比较的指针属于同一个数组:
当比较两个指针时,结果取决于相对的 指向的对象的地址空间中的位置。如果两个 指向对象类型的指针都指向同一个对象,或者都指向 超过同一数组对象的最后一个元素,它们比较 平等的。如果指向的对象是同一聚合的成员 对象,指向稍后声明的结构成员的指针比较更大 而不是指向结构中较早声明的成员的指针,并且 指向具有较大下标值的数组元素的指针比较 大于指向同一数组元素的指针 下标值。指向同一联合对象成员的所有指针 比较相等。如果表达式 P 指向数组的元素 对象和表达式 Q 指向同一对象的最后一个元素 数组对象,指针表达式 Q+1 比较大于 P 。在 在所有其他情况下,行为未定义。
OTOOH,我发现 N2346/6.5.8p4 与具有灵活数组成员的结构的定义相矛盾:
对于这些运算符,指向对象的指针是 不是数组元素的行为与指向第一个元素的指针相同 长度为 1 的数组的元素,对象的类型为其 元素类型。
这意味着由于struct inotify_event *first_event 永远不是N2346/6.7.2.1p3 数组的元素,因此它可以被视为长度为1 的数组的元素,这与N2346/6.7.2.1p3 矛盾
【问题讨论】:
-
C 标准没有定义将它们与
<、>、<=或>=进行比较的行为。以通常的方式将它们与==或!=进行比较。 (这无疑是 C 标准的意图,不管对措辞有任何疑问,也不管它是否可以被视为长度为 1 的数组。) -
@EricPostpischil 是的,我没有考虑
6.5.9p6:两个指针比较相等当且仅当两个指针都是空指针,都是指向同一个对象的指针(包括指向一个对象的指针及其开头的子对象)或函数[...] -
由于
ino_buf指向struct inotify_event类型的4096 个结构的数组(name的长度为零),您应该能够同时比较first_event和second_event,只要它们指向该数组或在该数组后面。但是,因为您偏移了第二个指针,所以它大多不会对齐。 -- 我认为6.7.2.1p3强调的部分是指在编译时无法确定这样一个结构的大小。
标签: c arrays struct language-lawyer flexible-array-member