Est-ce une utilisation non valide de limiter les pointeurs?
-
27-09-2019 - |
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 ()?
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
, laissezL
être une lvalue qui a&L
basé sur P. SiL
est utilisé pour accéder à la valeur de l'X
objet qu'il désigne, etX
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 surP
.- Chaque accès qui modifie
X
est considéré également modifierP
, aux fins du présent paragraphe.- Si
P
est attribué la valeur d'unE
d'expression de pointeur qui est basé sur un autre objet pointeur restreintP2
, associé àB2
bloc, puis soit l'exécution deB2
commence avant l'exécution deB
, ou l'exécution deB2
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 P
← b
, B
← foo
, P2
← array
, B2
← bar
. 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