Quand un pointeur vers un type particulier ( par exemple int
, char
, float
, ..) est incrémentée, la valeur est augmentée de la taille de ce type de données. Si un void
pointeur qui pointe vers des données de taille x
est incrémenté, comment parvient-il à pointer les x
octets en avant? Comment le compilateur sait-il ajouter x
à la valeur du pointeur?
c
pointers
void-pointers
pointer-arithmetic
Siva Sankaran
la source
la source
void
pointeur qui pointe vers des données de taillex
est incrémenté, comment parvient-il à pointer lesx
octets en avant?" Ce n'est pas le cas. Pourquoi les personnes qui ont de telles questions ne peuvent-elles pas les tester avant de les poser - vous savez, au moins au strict minimum où elles vérifient si elles se compilent réellement, ce qui n'est pas le cas. -1, je ne peux pas croire que cela a obtenu +100 et -0.Réponses:
Conclusion finale: l'arithmétique sur a
void*
est illégale en C et C ++.GCC l'autorise comme extension, voir Arithmétique sur
void
- et pointeurs de fonction (notez que cette section fait partie du chapitre "Extensions C" du manuel). Clang et ICC autorisent probablement l'void*
arithmétique à des fins de compatibilité avec GCC. D'autres compilateurs (comme MSVC) interdisent l'arithmétique survoid*
, et GCC l'interdit si l'-pedantic-errors
indicateur est spécifié, ou si l'-Werror-pointer-arith
indicateur est spécifié (cet indicateur est utile si votre base de code doit également compiler avec MSVC).La norme C parle
Les citations sont tirées du projet n1256.
La description standard de l'opération d'ajout indique:
Donc, la question ici est de savoir si
void*
est un pointeur vers un "type d'objet", ou de manière équivalente, s'ilvoid
s'agit d'un "type d'objet". La définition du "type d'objet" est:Et la norme définit
void
comme:Puisqu'il
void
s'agit d'un type incomplet, ce n'est pas un type d'objet. Ce n'est donc pas un opérande valide pour une opération d'addition.Par conséquent, vous ne pouvez pas effectuer d'arithmétique de pointeur sur un
void
pointeur.Remarques
À l'origine, on pensait que l'
void*
arithmétique était autorisée, en raison de ces sections de la norme C:cependant,
Cela signifie donc que cela
printf("%s", x)
a la même signification, qu'ilx
soit de typechar*
ouvoid*
, mais cela ne signifie pas que vous pouvez faire de l'arithmétique sur unvoid*
.Note de l'éditeur: Cette réponse a été modifiée pour refléter la conclusion finale.
la source
void*
arithmétique des pointeurs n'est pas autorisée. GCC a une extension qui permet de faire cela.void*
arithmétique (du moins par défaut).L'arithmétique des pointeurs n'est pas autorisée sur les
void*
pointeurs.la source
void
est un type incomplet qui ne peut jamais être complété par définition.transtypez-le en pointeur char et incrémentez votre pointeur en avant de x octets.
la source
char
, l'incrémentation dex
, puis la réinterprétation de la nouvelle valeur comme un autre type est à la fois un comportement inutile et indéfini.man 3 qsort
devrait avoir levoid qsort(void *base, size_t nmemb, size_t size, [snip])
, alors vous n'avez aucun moyen de connaître le "bon type"La norme C n'autorise pas l' arithmétique des pointeurs vides . Cependant, GNU C est autorisé en considérant la taille de void est
1
.Norme C11 §6.2.5
Paragraphe - 19
Le programme suivant fonctionne bien dans le compilateur GCC.
Peut-être que d'autres compilateurs génèrent une erreur.
la source
Vous ne pouvez pas faire d'arithmétique de pointeur sur les
void *
types, exactement pour cette raison!la source
Vous devez le convertir en un autre type de pointeur avant d'effectuer l'arithmétique du pointeur.
la source
Les pointeurs vides peuvent pointer vers n'importe quel bloc de mémoire. Par conséquent, le compilateur ne sait pas combien d'octets incrémenter / décrémenter lorsque nous tentons d'arithmétique de pointeur sur un pointeur void. Par conséquent, les pointeurs vides doivent d'abord être transtypés vers un type connu avant de pouvoir être impliqués dans une arithmétique de pointeur.
la source
Le compilateur connaît par type cast. Étant donné un
void *x
:x+1
ajoute un octet àx
, le pointeur passe à l'octetx+1
(int*)x+1
ajoute dessizeof(int)
octets, le pointeur passe à l'octetx + sizeof(int)
(float*)x+1
addressizeof(float)
octets, etc.Bien que le premier élément ne soit pas portable et soit contre le Galateo de C / C ++, il est néanmoins correct en langage C, ce qui signifie qu'il se compilera en quelque chose sur la plupart des compilateurs nécessitant éventuellement un drapeau approprié (comme -Wpointer-arith)
la source
Althought the first item is not portable and is against the Galateo of C/C++
Vrai.it is nevertheless C-language-correct
Faux. C'est une double pensée! L'arithmétique du pointeurvoid *
est syntaxiquement illégale, ne doit pas se compiler et produit un comportement indéfini si c'est le cas. Si un programmeur imprudent peut le faire compiler en désactivant un avertissement, ce n'est pas une excuse.unsigned char*
par exemple, ajouter unesizeof
valeur à un pointeur.