Tableaux consécutifs

Aug 26 2020

Je suis curieux de connaître une phrase de la norme C18:

Deux pointeurs se comparent égaux si et seulement si les deux sont des pointeurs nuls, les deux sont des pointeurs vers le même objet (y compris un pointeur vers un objet et un sous-objet à son début) ou une fonction, les deux sont des pointeurs vers un après le dernier élément du même tableau objet, ou l'un est un pointeur vers un après la fin d'un objet tableau et l'autre est un pointeur vers le début d'un autre objet tableau qui suit immédiatement le premier objet tableau dans l'espace d'adressage. § 6.5.9 6

Pourquoi l'objet suivant le tableau doit-il nécessairement être un autre tableau? Ne pourrait pas simplement être un objet du même type que le type de base du tableau (comme un intimmédiatement suivant int[])?

Pas étonnant que j'aie essayé ce code:

#include <stdio.h>

struct test { int arr[10]; int i; };

int main() {
    struct test t;
    int *p, *q;
    p = t.arr + 10;
    q = &t.i;
    if (p == q)
        printf("Equal pointers.");
    return 0;
}

Et cela donne des pointeurs égaux. Ce comportement n'est-il pas garanti du tout, juste une coïncidence définie par l'implémentation?

Réponses

24 chux-ReinstateMonica Aug 26 2020 at 17:41

OP: Pourquoi l'objet suivant le tableau doit-il nécessairement être un autre tableau?

Ce ne est pas. "... début d'un tableau différent ..." est une simplification. La prochaine spécification est:

Pour les besoins de ces opérateurs, un pointeur vers un objet qui n'est pas un élément d'un tableau se comporte de la même manière qu'un pointeur vers le premier élément d'un tableau de longueur un avec le type de l'objet comme type d'élément. C17dr § 6.5.9 7


OP: Ne pourrait pas être simplement un objet dont le type était le même que le type de base du tableau (comme un intimmédiatement suivant int[])?

Oui.

8 th33lf Aug 26 2020 at 17:26

Premièrement, la spécification d'un tableau ici n'exclut / n'interdit pas un seul objet. Un seul objet en mémoire est impossible à distinguer d'un tableau de taille 1.

( Modifier : lisez cette réponse pour une citation de la norme qui le déclare explicitement en se référant aux pointeurs)

Deuxièmement, la norme tente également de clarifier la déclaration que vous avez citée, la note de bas de page suivante indiquant les scénarios dans lesquels la règle s'applique:

Deux objets peuvent être adjacents en mémoire car ce sont des éléments adjacents d'un plus grand tableau ou des membres adjacents d'une structure sans remplissage entre eux, ou parce que l'implémentation a choisi de les placer ainsi, même s'ils ne sont pas liés.

En mettant tout cela ensemble, ce que la norme essaie de dire ici, c'est qu'en général, deux pointeurs vers des objets différents ne devraient pas se comparer égaux. Cependant, comme il est légal de pointer un au-delà d'un objet tableau en mémoire, s'il se trouve qu'il y a un objet (tableau) différent à cet emplacement, il est toujours légal pour un tel pointeur de comparer égal à un pointeur vers l'objet adjacent. Maintenant, il peut y avoir ou non un objet valide à cet emplacement, en raison des choix d'alignement et du remplissage, mais s'il y en a un, il est acceptable que ces pointeurs se comparent égaux.

Dans votre exemple, si je changeais le tableau en char, les pointeurs se compareraient probablement de manière inégale car le compilateur choisirait d'aligner l'int à 4 octets (sur la plupart des plates-formes 32 ou 64 bits), introduisant ainsi un remplissage. Ce comportement est toujours légal selon la norme.

#include <stdio.h>

struct test { char arr[10]; int i; };

int main() {
    struct test t;
    int *p, *q;
    p = (int*)(t.arr + 10);
    q = &t.i;
    if(p == q)
      printf("Equal pointers.");
    else
      printf("Unequal pointers.");
    return 0;
}