Comment convertir un pointeur en “void *” deux fois peut-il être invalide?

En ce qui concerne la réponse de zwol , je ne comprends pas pourquoi

typedef void (*fp)(void); // any pointer-to-function type will show this effect fp c = (void *)(void *)0; // invalid conversion in both C and C++ 

Comment la dernière ligne est-elle invalide? Pour moi, cela ressemble à la conversion de int(0) en void* deux fois, où la conversion d’un pointeur vers le même type devrait suffire, comme ceci:

 int a, *pa = (int*)&a; // ^^^^^^ Totally OK 

La question dont vous parlez est un exemple artificiel, destiné à illustrer un exemple des règles de C, et la règle invalide n’est pas la double dissortingbution, c’est la tâche à accomplir.

Si vous avez un type de pointeur vers une fonction, tel que

 typedef void (*fp)(void); 

vous pouvez initialiser des variables de ce type avec n’importe quelle constante de pointeur null valide, par exemple

 fp a = 0; // canonical null pointer constant in C fp b = (void *)0; // another common choice fp c = '\0'; // yes, really, this is a null pointer constant fp d = (1-1); // and so is this 

Mais vous ne pouvez pas les initialiser avec un pointeur sur un type spécifique autre que fp , même si ce pointeur est un pointeur nul et même si le type spécifique en question est void * .

 char *x = 0; void *y = 0; fp e = x; // invalid: no assignment conversion from `char *` to `fp` fp f = y; // invalid: no assignment conversion from `void *` to `fp` 

La ligne de mon ancienne réponse par laquelle vous avez été confus,

 fp g = (void *)(void *)0; 

est essentiellement le même que fp f = y ci-dessus. Le côté droit des deux affectations est un pointeur null de type void * , mais pas une constante de pointeur nul. L’ affectation n’est donc pas valide.

Vous vous demandez probablement maintenant pourquoi (void *)(void *)0 n’est pas une constante de pointeur nulle, même si (void *)0 est une constante de pointeur nulle. C’est ainsi que le standard C s’écrit: une constante de pointeur nulle est définie comme toute expression constante de type entier ayant la valeur 0, éventuellement avec une conversion vers void * devant celle-ci. Toute dissortingbution supplémentaire et ce n’est plus une constante de pointeur nulle (mais une expression constante). (Les expressions constantes entières ne peuvent pas contenir d’incidents internes en types de pointeur.)

Dans votre exemple contrasté

 int a; int *pa = (int *)&a; 

aucun pointeur null n’est impliqué, aucune expression constante entière non plus, et la conversion est réellement redondante à 100%. &a pourrait être une expression constante (si et seulement si a a une durée de stockage statique), mais ce n’est pas une expression constante entière .