Violation d’alias ssortingcte ou violation d’alignement avec une structure avec un membre de tableau flexible?

Imaginez une structure comme celle-ci:

struct test_s { int i; size_t namelen; char name[]; }; 

Maintenant, je voudrais renvoyer un tableau de ces structures en code utilisateur, en utilisant également une fonction générique qui prend un pointeur void * :

 size_t test_read(void *buf, size_t bufsize); 

Chacun des éléments du tableau doit être aligné sur l’alignement de la struct s_s . Dans chaque élément du tableau, la namelen est ajustée. Elle est donc supérieure ou égale à strlen(name) , mais avec des octets “inutilisés” supplémentaires entre les membres du tableau, de sorte que le prochain membre du tableau commence à la banque de mémoire divisable par alignof(struct s_s) .

Donc, nous pouvons savoir / affirmer qu’ayant n’importe quelle struct test_s *t il est vrai que t->namelen % alignof(struct test_s) == 0 et t->namelen == 0 || t->namelen >= strlen(t->name) t->namelen == 0 || t->namelen >= strlen(t->name) .

Maintenant, image qui test_read renvoie 4 struct test_s . Nous pouvons les parcourir, mais en ajoutant à chaque boucle la sizeof(struct test_s) et en ajoutant le t->namelen du membre déjà traité pnt += sizeof(struct test_s) + t->namelen . Les octets “de remplissage” “inutilisés” entre les membres du tableau et les chaînes ne sont pas initialisés et le but est de ne jamais y accéder.

 #include  #include  #include  #include  #include  #include  #include  // out structure struct test_s { int i; size_t namelen; char name[]; }; // stores an struct test_s object into buf and after it stores ssortingng as pointed to by name // returns sizeof(struct test_s) + strlen(name) size_t test_init(void *buf, size_t bufsize, int i, const char name[]) { assert(buf != NULL); assert(bufsize > sizeof(struct test_s)); size_t namelen; // if (t->namelen == 0) { that means that t->name is empty. } if (name) { namelen = strlen(name) + 1; assert(bufsize > sizeof(struct test_s) + namelen * sizeof(*((struct test_s*)0)->name)); } else { namelen = 0; } struct test_s * const t = buf; t->i = i; t->namelen = namelen; memcpy(t->name, name, namelen); return sizeof(*t) + namelen * sizeof(*t->name); } // works as test_init, but returned value is incremented to // make the `buf + returned value` aligned to struct test_s size_t test_init_aligned(void *buf, size_t bufsize, int i, const char name[]) { const size_t copied = test_init(buf, bufsize, i, name); // align the end of the struct to be aligned with struct test_s struct test_s * const t = buf; const size_t tmp = copied % alignof(struct test_s); const size_t to_aligned = tmp ? alignof(struct test_s) - tmp : 0; t->namelen += to_aligned; const size_t aligned_size = copied + to_aligned; return aligned_size; } // returns multiple struct test_s objects and stores them in buf // returns number of bytes written size_t test_read(void *buf, size_t bufsize) { char * const outbeg = buf; char *out = buf; char * const outend = &out[bufsize]; out += test_init_aligned(out, outend - out, 1, "first element"); out += test_init_aligned(out, outend - out, 2, "second element"); out += test_init_aligned(out, outend - out, 3, "third element"); out += test_init_aligned(out, outend - out, 4, NULL); return out - outbeg; } int main() { // our read buffer char alignas(struct test_s) buf[1024]; // read structs test_s with ssortingngs into our buffer const size_t readlen = test_read(buf, sizeof(buf)); const struct test_s *test = NULL; const char *pnt = NULL; for (pnt = &buf[0]; pnt namelen * sizeof(*test->name)) { test = (const struct test_s *)pnt; printf("i=%d len=%2zu name='%s'\n", test->i, test->namelen, test->namelen != 0 ? test->name : "" ); } } 
  1. Ce code comporte-t-il des violations d’aliasing ssortingctes?
  2. Ce code peut-il non aligné accéder à des objects?
  3. Ce code a-t-il des comportements indéfinis?
  4. Ce code est basé sur l’exemple de man 7 inotify et je voulais qu’il soit très similaire. L’exemple présenté itère sur struct inotify_event utilisant le même principe. Cet exemple présente-t-il des comportements non définis?

Je dis qu’il n’y a pas de violation de crénelage ssortingcte. Je n’accède jamais à un object sous-jacent à l’aide de pointeurs différents. Les pointeurs sont toujours struct test_s* et char* , bien que l’arithmétique soit effectuée à l’aide de char* pointeurs.

Version en direct du code disponible sur onlinegdb .

La question provient des commentaires de cette question .