0

質問: 2 つのポインターを柔軟な配列メンバーと比較して、より多く (より少なく) 等しいかどうかを比較することは正当ですか?


struct inotify_eventLinux での宣言方法は次のとおりです。

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(emp. mine):

複数の名前付きメンバーを持つ構造体の最後のメンバーは、不完全な配列型を持つ可能性があります。そのような構造体 (およびそのような構造体であるメンバーをおそらく再帰的に含む共用体) は、構造体のメンバーまたは配列の要素であってはなりません

OTOH、N2346/6.5.8p5比較される必要なポインターは同じ配列に属します:

2 つのポインターを比較すると、結果は、指しているオブジェクトのアドレス空間内の相対位置によって異なります。オブジェクト型への 2 つのポインターが両方とも同じオブジェクトを指している場合、または両方が同じ配列オブジェクトの最後の要素の 1 つ後ろを指している場合、それらは等しいと比較されます。指しているオブジェクトが同じ集合体オブジェクトのメンバーである場合、後で宣言された構造体メンバーへのポインターは、構造体で以前に宣言されたメンバーへのポインターよりも大きく、添字値が大きい配列要素へのポインターは、同じ配列の要素へのポインターよりも大きくなります。より低い添字値で。同じ共用体オブジェクトのメンバーへのすべてのポインターは等しいと比較されます。式 P が配列オブジェクトの要素を指し、式 Q が同じ配列オブジェクトの最後の要素を指す場合、ポインター式 Q+1 は P より大きいと比較されます。それ以外の場合、動作は未定義です。

N2346/6.5.8p4OTOOH、柔軟な配列メンバーを持つ構造体の定義と矛盾することがわかりました。

これらの演算子の目的上、配列の要素ではないオブジェクトへのポインターは、要素の型としてオブジェクトの型を持つ長さ 1 の配列の最初の要素へのポインターと同じように動作します。

struct inotify_event *first_eventは配列の要素ではないN2346/6.7.2.1p3ため、長さ 1 の配列の要素と見なすことができるため、矛盾することを意味します。N2346/6.7.2.1p3

4

1 に答える 1