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.

  1. 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();
    }
    
  2. 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

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top