L'arithmétique des pointeurs pour les nuls pointeur en C
Lorsqu'un pointeur vers un type particulier (disons int
, char
, float
, ..) est incrémenté, sa valeur est augmentée par la taille de ce type de données. Si un void
pointeur qui pointe vers les données de taille x
est incrémenté, comment fait-il pour point x
octets à l'avance? Comment le compilateur de savoir à ajouter x
à la valeur du pointeur de la souris?
- double possible de Erreur d'Exécution de l'Arithmétique Pointeur sur void * dans MSVC
- La question sonne comme si elle suppose que le compilateur(/run-time) sait quel type d'objet, le pointeur a été mis à, et ajoute à sa taille pour le pointeur. C'est un malentendu: il ne connaît que l'adresse.
- "Si un
void
pointeur qui pointe vers les données de taillex
est incrémenté, comment fait-il pour pointx
octets à l'avance?" Il n'a pas. Pourquoi pas des gens qui ont de telles questions de les tester avant de vous poser la question: tu sais, au moins pour le strict minimum où ils vérifient s'il en fait la compile, ce qui ne l'est pas. -1, ne peut pas croire que cela fait +de 100 et de 0.
Vous devez vous connecter pour publier un commentaire.
Conclusion finale: l'arithmétique sur un
void*
est illégale en C et C++.GCC permet comme une extension, voir L'arithmétique sur
void
et la Fonction des Pointeurs (notez que cette section est une partie de la "C" Extensions chapitre de ce manuel). Clang et de la CCI, susceptibles de permettrevoid*
arithmétique pour les fins de compatibilité avec GCC. D'autres compilateurs (tels que MSVC) refuser l'arithmétique survoid*
, et GCC ne l'autorise pas si le-pedantic-errors
drapeau est spécifié, ou si le-Werror-pointer-arith
drapeau est spécifié (cette option est utile si votre base de code doit également compiler avec MSVC).Le C Standard Parle
Citations sont tirées de la n1256 projet.
Le standard de description de l'opération d'addition états:
Donc, la question qui se pose ici est de savoir si
void*
est un pointeur vers un "type d'objet", ou, de manière équivalente, sivoid
est un "type d'objet". La définition de "type d'objet" est:Et la norme définit
void
comme:Depuis
void
est un type incomplète, il n'est pas un type d'objet. Il n'est donc pas valide opérande à une opération d'addition.Par conséquent, vous ne pouvez pas effectuer l'arithmétique des pointeurs sur un
void
pointeur.Notes
À l'origine, on pensait que
void*
l'arithmétique a été autorisée, en raison de ces sections de la norme C:Cependant,
Cela signifie donc que
printf("%s", x)
a la même signification quex
a 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é pour refléter la conclusion finale.
void*
de l'arithmétique des pointeurs n'est pas autorisé. GCC est un extension qui permet de faire cela.-Werror-pointer-arith
comme une option de ligne de commande pour les bras-xilinx-linux-gnueabi-g++, mais il n'a pas été reconnu. Lorsque ce drapeau a été ajouté à gcc? Où puis-je trouver plus d'infos/une liste de drapeaux?{clang|gcc} -Wpedantic -Werror -Wall -ansi foo.c
-std=c99
(ou c11) au lieu de-ansi
.-ansi
fait GCC utiliser la norme C89, qui est ancienne, et a laide des limites, par exemple en exigeant que toutes les déclarations de variables au début d'un bloc. Utilisez uniquement C89 si vous avez pour...void*
de l'arithmétique (au moins par défaut).void *
est un peu, de cette façon, l'arithmétique des pointeurs survoid *
serait une opération au niveau du bit.Werror-pointer-arith
au lieu de carrément défaut pour la compilation (comme il se doit).De l'arithmétique des pointeurs n'est pas autorisée sur
void*
pointeurs.void
est un type incomplète qui ne peut jamais être rempli par définition.convertir un pointeur de char un incrémenter le pointeur de la souris vers l'avant x octets à l'avance.
char
, l'incrémentation parx
, puis de réinterpréter la nouvelle valeur comme un autre type est à la fois inutile et comportement 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 savoir le "bon type"Vous ne pouvez pas faire de l'arithmétique des pointeurs sur
void *
types, exactement pour cette raison!La C standard ne permet pas vide l'arithmétique des pointeurs. Cependant, GNU C est autorisé par compte tenu de la taille de vide est
1
.C11 standard §6.2.5
Paragraphe 19
Programme suivant fonctionne très bien dans le compilateur GCC.
Peut-être d'autres compilateurs génèrent une erreur.
Vous devez le convertir en un autre type de pointeur avant de faire de l'arithmétique des pointeurs.
Vide pointeurs peut pointer vers n'importe quel morceau de la mémoire. Donc le compilateur ne sait pas combien d'octets pour incrémenter/décrémenter lorsque l'on tente de l'arithmétique de pointeur sur un pointeur void. Donc nul pointeurs doivent d'abord être identifié à un type connu avant qu'ils peuvent être impliqués dans toute l'arithmétique des pointeurs.
Compilateur sait par type de fonte. Étant donné un
void *x
:x+1
ajoute un octet àx
, pointeur va à l'octetx+1
(int*)x+1
ajoutesizeof(int)
octets, pointeur va à l'octetx + sizeof(int)
(float*)x+1
adressesizeof(float)
octets,etc.
Bien que le premier élément n'est pas portable et qui est contre le Galateo de C/C++, il est néanmoins langage C-corriger en ce sens qu'elle permettra de compiler quelque chose sur la plupart des compilateurs, éventuellement, nécessitant un indicateur approprié (comme-Wpointer-arith)
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 doublethink! L'arithmétique des pointeurs survoid *
est illégale du point de vue syntaxique, ne devrait pas compiler, et produit un comportement indéterminé si il n'. Si imprudente par le programmeur peut faire compiler par la désactivation de certaines avertissement, qui n'est pas une excuse.unsigned char*
par exemple ajouter unesizeof
de la valeur à un pointeur.