Restreintes questions pointeur
-
25-09-2019 - |
Question
Je suis un peu confus au sujet des règles en ce qui concerne les pointeurs restreints. Peut-être quelqu'un là-bas peut me aider.
-
Est-il légal de définir des pointeurs restreints imbriqués comme suit:
int* restrict a; int* restrict b; a = malloc(sizeof(int)); // b = a; <-- assignment here is illegal, needs to happen in child block // *b = rand(); while(1) { b = a; // Is this legal? Assuming 'b' is not modified outside the while() block *b = rand(); }
-
Est-il légal pour obtenir une valeur de pointeur restreint comme suit:
int* restrict c; int* restrict d; c = malloc(sizeof(int*)*101); d = c; for(int i = 0; i < 100; i++) { *d = i; d++; } c = d; // c is now set to the 101 element, is this legal assuming d isn't accessed? *c = rand();
Merci! Andrew
La solution
Pour référence, voici la définition de qualificatif restrict
plutôt alambiquée (de C99 6.7.3.1 « définition formelle de restreindre »):
Soit D une déclaration d'un ordinaire identificateur qui fournit un moyen de la désignation d'un objet P en tant que pointeur restreindre qualifié de type T.
Si D apparaît à l'intérieur d'un bloc et n'a pas la classe de stockage extern, soit B représentent le bloc. Si D apparaît dans la liste des paramètres déclarations d'une fonction définition, Soit B la bloc associé. Sinon, laissez-B désigner le bloc de base (ou le bloc quelle que soit la fonction est appelée à démarrage du programme dans une pose libre environnement).
Dans ce qui suit, un pointeur expression E est dit être basé sur objet P if (à un moment donné de séquence dans l'exécution de B avant le évaluation de E) modifiant au point P une copie de l'objet de réseau en dont elle a autrefois changerait la valeur de E. Notez que « base » est défini uniquement pour les expressions avec types de pointeur.
Lors de chaque exécution de B, soit L tout lvalue qui a & L basé sur P. Si L est utilisée pour accéder à la valeur de la X objet qu'il désigne, et X est également modifié (par tout moyen), le prescriptions suivantes sont applicables: T doit ne pas être const qualifié. Tous les autres lValue utilisé pour accéder à la valeur de X doit aussi avoir son adresse sur la base P. Chaque accès qui modifie X doit être considéré également modifier P, pour Aux fins du présent paragraphe. Si p est affectée la valeur d'un pointeur expression E qui est basé sur un autre objet de pointeur P2 restreint, associé au bloc B2, puis soit l'exécution de B2 commence avant l'exécution de B, ou exécution de B2 prend fin avant la tâche. Si ces les exigences ne sont pas remplies, la comportement est indéfini.
Voici une exécution de B signifie que partie de l'exécution du programme qui correspondrait à la durée de vie d'un objet de type scalaire et la durée de stockage automatique associé à B.
Ma lecture de ce qui précède signifie que, dans votre première question, a
ne peut pas être attribué à b
, même à l'intérieur d'un bloc « enfant » - le résultat est indéfini. Une telle cession pourrait être faite si b
ont été déclarés dans ce « sous-bloc », mais depuis b
est déclarée à la même portée que a
, ne peut pas être la cession.
Pour la question 2, les missions entre c
et d
se traduisent également par un comportement non défini (dans les deux cas).
Le bit correspondant de la norme (pour les deux questions) est:
Si P est attribué la valeur d'une expression pointeur E qui est basé sur Un autre objet de pointeur restreint P2, associé au bloc B2, puis soit l'exécution de B2 commence avant l'exécution de B, ou exécution de B2 prend fin avant l'affectation.
Étant donné que les pointeurs restreints sont associés au même bloc, il est impossible pour le bloc B2 pour commencer avant l'exécution de B, ou pour B2 mettre fin avant la cession (puisque B et B2 sont le même bloc).
La norme donne un exemple qui rend ce assez clair (je pense - la clarté de 4 courts paragraphes de la définition de restrict
est à égalité avec les règles de résolution de noms de C ++):
Exemple 4:
La règle qui limite les affectations entre pointeurs restreints ne pas distinguer entre un appel de fonction et un bloc imbriqué équivalent. À une exception près, seulement affectations « externe à interne » entre pointeurs restreints déclarés dans imbriquée les blocs ont un comportement défini.
{ int * restrict p1; int * restrict q1; p1 = q1; // undefined behavior { int * restrict p2 = p1; // valid int * restrict q2 = q1; // valid p1 = q2; // undefined behavior p2 = q2; // undefined behavior } }
Autres conseils
Le qualificatif de type restrict
est indication au compilateur que, si la mémoire adressée par le pointeur restrict
qualifié est modifié, aucun autre pointeur accédera à cette même mémoire. Le compilateur peut choisir d'optimiser le code impliquant des pointeurs de restrict
qualifiés d'une manière qui pourrait autrement entraîner un comportement incorrect. Il est de la responsabilité du programmeur de veiller à ce que comme ils sont utilisés pointeurs restrict-qualifiés ont été destinés à être utilisés. Dans le cas contraire, un comportement non défini peut en résulter. ( lien )
Comme vous pouvez le voir dans la description ci-dessus, vos deux missions sont illégales, qui peuvent travailler dans executables produits par certains compilateurs mais briser dans d'autres. Ne vous attendez pas le compilateur lui-même d'émettre des erreurs ou des avertissements comme restrict
donne juste l'occasion d'effectuer certains optimisation, qu'il peut choisir de ne pas effectuer, comme dans le cas de volatile
.