【问题标题】:Comparing 2 pointers to a struct with a flexible array member比较 2 个指向具有灵活数组成员的结构的指针
【发布时间】: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 标准没有定义将它们与&lt;&gt;&lt;=&gt;= 进行比较的行为。以通常的方式将它们与==!= 进行比较。 (这无疑是 C 标准的意图,不管对措辞有任何疑问,也不管它是否可以被视为长度为 1 的数组。)
  • @EricPostpischil 是的,我没有考虑6.5.9p6两个指针比较相等当且仅当两个指针都是空指针,都是指向同一个对象的指针(包括指向一个对象的指针及其开头的子对象)或函数[...]
  • 由于ino_buf 指向struct inotify_event 类型的4096 个结构的数组(name 的长度为零),您应该能够同时比较first_eventsecond_event,只要它们指向该数组或在该数组后面。但是,因为您偏移了第二个指针,所以它大多不会对齐。 -- 我认为6.7.2.1p3强调的部分是指在编译时无法确定这样一个结构的大小。

标签: c arrays struct language-lawyer flexible-array-member


【解决方案1】:

如果T 是一个包含灵活数组成员的结构,则不能声明T[intVal] 形式的对象或类型;这是一个编译时约束,如果程序试图声明这样一个数组,则要求编译器发出诊断。

标准的一个单独部分指定指向T 类型对象的指针的行为与指向T[1] 类型对象的指针一样。我认为在合理适用的情况下,我不打算将具有灵活数组成员的结构排除在该条款之外。尝试声明 T[1] 类型的对象或 typedef 将违反约束,需要进行诊断,并且不可能有两个属于同一数组的 T 类型的不匹配指针,但是质量实现没有理由不处理指向同一类型 T 对象的两个指针之间的关系比较,因为它们会处理指向同一数组的同一元素的两个指针之间的比较。

【讨论】:

    猜你喜欢
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    相关资源
    最近更新 更多