Question

Supposons que j'ai grand tableau I qui calcule un index dans et passe à une seconde fonction. A titre d'exemple simple, quelque chose comme:

void foo(float* array, float c, unsigned int n)
{
    for (unsigned int i = 0; i < n; ++i)
        array[i] *= c;
}

void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int n)
{
    for (unsigned int i = 0; i < m; ++i)
        foo(&array[i * n], array2[i], n);
}

Est-ce enfreint les règles pour limiter dans le bar () où vous passez l'adresse d'une partie du tableau à foo (), même si vous jamais vraiment utiliser l'alias pour une partie du tableau dans la barre ()?

Était-ce utile?

La solution

(Toutes les citations se réfèrent à N1256 , qui est C99, plus rectificatifs technique (TC3).)

La définition formelle de restrict est donnée dans §6.7.3.1. Je cite le plus important de paragraphe ci-dessous. P est un pointeur restrict qualifié du type T dont la portée est un B de bloc. Une expression de pointeur E est dit basé sur P si elle dépend de la valeur de P elle-même, et non pas la valeur que les points de P à.

  

Lors de chaque exécution de B, laissez L être une lvalue qui a &L basé sur P. Si L est utilisé pour accéder à la valeur de l'X objet qu'il désigne, et X est également modifié (par tout moyen), le conditions suivantes sont applicables:

     
      
  • T ne doit pas être const qualifié.
  •   
  • Toutes les autres lvalue utilisé pour accéder à la valeur de X doit aussi avoir son adresse basée sur P.
  •   
  • Chaque accès qui modifie X est considéré également modifier P, aux fins du présent paragraphe.
  •   
  • Si P est attribué la valeur d'un E d'expression de pointeur qui est basé sur un autre objet pointeur restreint P2, associé à B2 bloc, puis soit l'exécution de B2 commence avant l'exécution de B, ou l'exécution de B2 prend fin avant la cession.
  •   
     

Si ces exigences ne sont pas remplies, le comportement est indéfini.


regard Let à ce que les règles ont à dire sur les accès à certaines parties du bar de array dans foo. Nous commençons par array, un pointeur restreindre qualifié a déclaré dans la liste des paramètres de bar. Pour plus de clarté, je alpha-convertir les paramètres de foo:

void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }

Le stockage pointé par array est également modifiée par b. C'est ok avec le deuxième point que &array[i*n] équivaut à array+(i*n) (voir §6.5.3.2).

Si b était restreint qualifié , alors nous devrions vérifier le quatrième point avec Pb, Bfoo, P2array, B2bar. Depuis B est imbriqué dans B2 (fonctions se comportent comme si inline ici, voir §6.7.3.1.11), la première condition est remplie. Il y a aussi une instanciation du troisième point (l'accès à b[i] dans foo) qui n'est pas un problème.

Cependant b est restreint non qualifié. Selon §6.3.2.3.2, « Pour tout qualificatif q , un pointeur vers un non q de type peuvent être convertis aux qualifiés à un pointeur vers q Version du type aux qualifiés; les valeurs stockées dans les pointeurs d'origine et convertis doivent être égaux ». Par conséquent, la conversion de array+(i*n) à b est bien défini et a le sens évident, si le comportement du programme est défini. En outre, étant donné que b n'est pas restrict qualifié, il n'a pas besoin d'obéir à une condition de linéarité. Par exemple, le foo suivant est légal en combinaison avec bar:

void qux(float *v, float *w) {
    v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
    qux(b,b);
}

AJOUTÉE : Pour répondre à votre préoccupation spécifique « dans la barre () où vous passez l'adresse d'une partie du tableau à foo () », c'est un non-problème: restrict applique à la ppointeur, pas le tableau, et vous pouvez effectuer des opérations arithmétiques sur ce (point 2).

Autres conseils

Non, restreindre les moyens de ce tableau ne peut rien alias, vous pouvez passer des choses à la barre sans enfreindre les règles

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