Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Pourquoi peut-on incrémenter un pointeur sur void ?

9 réponses
Avatar
rixed
--- 8< -----

void toto(void) {
void *ptr = 0;
ptr ++;
}

----- >8 ---

$ gcc -W -Wall -std=c99 -pedantic -c toto.c
/tmp/toto.c:4: warning: wrong type argument to increment

Or, d'après la norme (le draft que j'ai sous la main) :

6.2.5 Types
[#18] The void type comprises an empty set of values; it is
an incomplete type that cannot be completed.

[#19] Any number of derived types can be constructed from
the object, function, and incomplete types, as follows:
(... pointers ...)


-> De ceci il ressort qu'un pointeur vers void est un pointeur vers un
type incmoplet (par opposition à un type objet et un type fonction).


6.5.2.4 Postfix increment and decrement operators
[#2] (...) See the discussions of
additive operators and compound assignment for information
on constraints, types, and conversions and the effects of
operations on pointers. (...)

6.5.6 Additive operators
[#2] For addition, either both operands shall have
arithmetic type, or one operand shall be a pointer to an
object type and the other shall have integer type.


-> De ceci il ressort qu'incrémenter un pointeur n'est possible que si
le pointeur pointe vers un type objet.

Cqfd : on ne peut pas incrémenter un pointeur vers void.

Qu'est-ce que j'ai mal compris ?

Il y a bien 6.2.3 qui dit ceci :

[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.

Mais je ne vois pas bien comment ca s'imbrique dans le raisonnement
ci-dessus.

9 réponses

Avatar
Targeur fou
wrote:

Salut,

--- 8< -----

void toto(void) {
void *ptr = 0;
ptr ++;


Heu oui, mais de combien de bytes avance t'on avec ptr ?
Je crois bien qu'il est nécessaire de connaitre le type de ce qui est
pointé pour savoir de combien on va avancer / reculer en mémoire avec
l'arithmétique des pointeurs.

}

----- >8 ---

$ gcc -W -Wall -stdÉ9 -pedantic -c toto.c
/tmp/toto.c:4: warning: wrong type argument to increment


Ahh ?! J'aurais parié une erreur et non un warning (bug ou régression
d'implem C99 ?).
error C2036: 'void *' : unknown size avec MSVC 6 (cl 12.00.8168).


Or, d'après la norme (le draft que j'ai sous la main) :

6.2.5 Types
[#18] The void type comprises an empty set of values; it is
an incomplete type that cannot be completed.

[#19] Any number of derived types can be constructed from
the object, function, and incomplete types, as follows:
(... pointers ...)


-> De ceci il ressort qu'un pointeur vers void est un pointeur vers un
type incmoplet (par opposition à un type objet et un type fonction).


6.5.2.4 Postfix increment and decrement operators
[#2] (...) See the discussions of
additive operators and compound assignment for information
on constraints, types, and conversions and the effects of
operations on pointers. (...)

6.5.6 Additive operators
[#2] For addition, either both operands shall have
arithmetic type, or one operand shall be a pointer to an
object type and the other shall have integer type.


-> De ceci il ressort qu'incrémenter un pointeur n'est possible que si
le pointeur pointe vers un type objet.


Oui.


Cqfd : on ne peut pas incrémenter un pointeur vers void.

Qu'est-ce que j'ai mal compris ?


Je penche plutôt vers un pb d'usage de gcc ou un bug dans ce dernier.

Il y a bien 6.2.3 qui dit ceci :

[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.


Peut-être, mais il s'agit de la repésentation de la variable
pointeur, on ne connait toujours pas ce qui est pointé, donc ce n'est
pas utile.

A+
Regis

Avatar
Frédéri MIAILLE
a écrit dans le message de
news:
--- 8< -----

void toto(void) {
void *ptr = 0;
ptr ++;
}

----- >8 ---

$ gcc -W -Wall -stdÉ9 -pedantic -c toto.c
/tmp/toto.c:4: warning: wrong type argument to increment
J'ai déjà rencontré ce cas là lors d'un passage de paramètre.



Or, d'après la norme (le draft que j'ai sous la main) :

6.2.5 Types
[#18] The void type comprises an empty set of values; it is
an incomplete type that cannot be completed.
Ici, on ne parle pas de pointeur.

Là, le type est celui plutôt utilisé dans le cadre d'un retour de fonction
ou de ses paramètres formels.
Pour établir un schéma explicite.


[#19] Any number of derived types can be constructed from
the object, function, and incomplete types, as follows:
(... pointers ...)

-> De ceci il ressort qu'un pointeur vers void est un pointeur vers un
type incmoplet (par opposition à un type objet et un type fonction).
Je dirais plutôt que le pointeur pointe vers quelque chose d'indéterminé au

moment ou on l'emploie.


6.5.2.4 Postfix increment and decrement operators
[#2] (...) See the discussions of
additive operators and compound assignment for information
on constraints, types, and conversions and the effects of
operations on pointers. (...)

6.5.6 Additive operators
[#2] For addition, either both operands shall have
arithmetic type, or one operand shall be a pointer to an
object type and the other shall have integer type.
Pour les additions, soit, ils sont tous les deux arithmétiques, soit ils

sont des pointeurs de type connus.
Tu sais que incrémenter un pointeur de type int va bouger ton pointeur de 4
octets, incrémenter un pointeur de type MonType va bouger le pointeur de
sizeof(MonType).


-> De ceci il ressort qu'incrémenter un pointeur n'est possible que si
le pointeur pointe vers un type objet.
Implicitement si le type est connu oui. Si il est (void *), le transtypage

explicite avant incrémentation est requis.

Cqfd : on ne peut pas incrémenter un pointeur vers void.
Non.



Qu'est-ce que j'ai mal compris ?

Il y a bien 6.2.3 qui dit ceci :

[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.
En gros, le pointeur void doit être considéré comme un pointeur de 8 bits ou

de type char *
L'expression :
void *MonFlux;
int iD;
MonFlux[i]3;
Va foirer parceque l'on ne sait pas ou est le 44 élément de MonFlux, la
taille de chaque élément étant inconnue.
un petit transtypage vers (char *) avant d'accéder à l'élément indiquera la
taille du décallage.
char *p=(char *)MonFlux;
p[i]3;
ou Encore
short *p2=(short *)MonFlux;
p2[i/2]3;


Mais je ne vois pas bien comment ca s'imbrique dans le raisonnement
ci-dessus.





--
Frédéri MIAILLE
fr.comp.lang.c
fr.comp.lang.c++
fr.comp.graphisme.programmation

Avatar
Marc Boyer
Le 13-12-2005, Targeur fou a écrit :
wrote:
Qu'est-ce que j'ai mal compris ?


Je penche plutôt vers un pb d'usage de gcc ou un bug dans ce dernier.


J'ai la flemme de chercher dans les archives, mais j'avais rencontré
le pb, et on m'avait dit que c'était plus un choix de la part
de l'équipe de gcc qu'un bug.

Marc Boyer
--
Entre le fort et le faible, c'est la liberte qui opprime et le droit
qui libere. Henri Lacordaire, Dominicain


Avatar
Targeur fou
Re,

[coupé]



Cqfd : on ne peut pas incrémenter un pointeur vers void.

Qu'est-ce que j'ai mal compris ?



Rien,

Il y a bien 6.2.3 qui dit ceci :

[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.




Après recherches, c'est bien gcc qui outrepasse la norme
volontairement. Il s'agit d'une extension qui considère que le type
pointé par void à la taille d'un char. C'est tout à fait différent
de ce que dit 6.2.3 item 27 ci-dessus, même si ça à l'air similaire
au premier abord. Le fait de spécifier l'option -pedantic ne fait
sortir que des warnings.

A+
Regis


Avatar
Jean-Marc Bourguet
"Targeur fou" writes:

Le fait de spécifier l'option -pedantic ne fait sortir que des
warnings.


-pedantic-errors

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Antoine Leca
In news:,
va escriure:
--- 8< -----

void toto(void) {
void *ptr = 0;
ptr ++;
}

----- >8 ---

$ gcc -W -Wall -stdÉ9 -pedantic -c toto.c
/tmp/toto.c:4: warning: wrong type argument to increment


OK. Quel est le problème ?

GCC rencontre une contruction sans signification évidente, et choisit de
donner un sens (à savoir de considérer qu'il s'agit d'un char* ; cela vient
du fait qu'au début de la norme ANSI, qui a introduit les void*, il y eut
une vague de conversion un peu brutale des char* en void* pour représenter
des pointeurs "bruts"; et il y avait du code qui manipulait des pointeurs
bruts, mais utilisait parfois les propriétés des pointeurs char*).


Or, d'après la norme (le draft que j'ai sous la main) :


Qu'est-ce la norme vient faire là-dedans ?

Tu veux faire un rapport de non-conformité ? pas la peine, la norme autorise
les compilateurs à donner du sens aux constructions non strictement
conformes (par contre, il faut émettre un diagnostic, et c'est fait ici).

Tu veux faire un rapport de bogue à GCC ? Pas besoin de la norme pour cela,
il est clair pour tout le monde (en 2005) que ce genre de code n'est pas
propre, mais la compatibilité ascendante (et la résistance au changement)
peut avoir des raisons que la raison ignore.


Cqfd : on ne peut pas incrémenter un pointeur vers void.


Non. La norme ne dit pas quel en est le résultat. TRÈS DIFFÉRENT.

La norme du langage C n'a pas tous les pouvoirs (on vit en démocratie ;-)).


Antoine

Avatar
Emmanuel Delahaye
--- 8< -----

void toto(void) {
void *ptr = 0;
ptr ++;
}

----- >8 ---

$ gcc -W -Wall -stdÉ9 -pedantic -c toto.c
/tmp/toto.c:4: warning: wrong type argument to increment


C'est une extension de gcc. Dans le temps, '-ansi -pedantic' la
désactivait. Apparement, maintenant, elle de fait que signaler...

Avec Borland C, ça ne compile pas du tout.

--
A+

Emmanuel Delahaye

Avatar
Targeur fou
Jean-Marc Bourguet wrote:
"Targeur fou" writes:

Le fait de spécifier l'option -pedantic ne fait sortir que des
warnings.


-pedantic-errors



Merci Jean-Marc,

donc il s'agissait bien de méconnaisssance dans l'utilisation de gcc.

A+
Regis


Avatar
Pierre Maurette
--- 8< -----

void toto(void) {
void *ptr = 0;
ptr ++;
}
Déjà, il me semble qu'une opération (sauf affectation et comparaison),

et en tous cas une incrémentation, sur un "null pointer" quel que soit
son type conduit à un UB.
Le "null pointeur" ne pouvant être l'adresse d'un objet, on ne peut
remplir les conditions donnant à l'arithmétique des pointeurs un
comportement défini.

A part ça, je pense que gcc préserve du code existant en ne rejetant
pas l'arithmétique sur les pointeurs void*, et que ce n'est pas très
bien. J'ajoute à Borland C cité par Emmanuel le compilateur Microsoft
qui refuse en expliquant sèchement mais justement: "size unknown".

Un cast qui définit le "pas" de l'arithmétique:

ptr = (void*)((type*)ptr + 1);

ou (si on sait ce qu'on fait):

ptr = (void*)((le_bon_type_entier)ptr + 1);

est un peu lourd dans le source mais ne change rien au code machine
produit, à part le rendre conforme à ce qu'on attend.

int a[] = {0,1,2,3,4};
void* ptr = a;
/* ...... */
ptr++;

Combien de programmeurs vont se faire baiser au moins la première fois
(celle où ça faiot mal) ?

--
Pierre Maurette