Existe-t-il des cas d’utilisation reposant sur une représentation entière de deux allocations différentes en C?

Par exemple, considérons l’extrait de code C suivant:

void *p = malloc(1); void *q = malloc(1); bool question = (uintptr_t) p == (uintptr_t) q; 

J’espère que tout le monde s’attend à ce que la question soit toujours fausse. (Étonnamment, la norme C11 ne l’exige pas. La seule ressortingction sur uintptr_t est par exemple ((void *) ((uintptr_t) p)) == p . Voir la section 7.20.1.4 de la norme C11 pour plus de détails.)

Ma question est la suivante: existe-t-il un cas d’utilisation réaliste reposant sur la garantie que la question est fausse ou, plus généralement, sur les représentations entières de deux allocations?

La question est imparfaite. Tout d’abord, considérons ce code (où nous supposons que malloc ne renvoie pas null):

 void *p = malloc(1); void *q = malloc(1); bool question = (uintptr_t) p == (uintptr_t) q; 

Selon la spécification uintptr_t du standard C 2011, si nous le faisons:

 void *p1 = (void *) (uintptr_t) p; void *q1 = (void *) (uintptr_t) q; 

Alors, p1 doit être égal à p et q1 à q . Et, selon la spécification standard de l’opérateur == , p1 et q1 ne doivent pas être comparés égaux, car ils sont respectivement égaux à p et à q et sont donc des pointeurs sur des objects différents.

Parce que (void *) (uintptr_t) p et (void *) (uintptr_t) q produisent des valeurs différentes, (uintptr_t) p et (uintptr_t) q doivent être des valeurs différentes. (En effet, la conversion en void * est une fonction mathématique du modèle C. Chaque fois qu’une valeur spécifique lui est atsortingbuée, dans les règles de C, elle produit un résultat qui est effectivement identique, dans les règles de C.) Donc (uintptr_t) p n’est pas égal à (uintptr_t) q .

Considérons maintenant ce code, où nous transformons void * en char * :

 char *p = malloc(1); char *q = malloc(1); bool question = (uintptr_t) p == (uintptr_t) q; 

La spécification de uintptr_t dit uintptr_t sur les conversions à partir de char * . De toute évidence, ces pointeurs sur char * peuvent être convertis en void * . Cependant, je ne vois pas que la norme exige qu’une conversion de char * en uintptr_t insère implicitement une conversion en void * ou se comporte comme si elle le faisait. Donc, je suppose que cela n’est pas techniquement défini par la norme. Mais je doute que vous trouviez une implémentation en C dans laquelle ceci diffère de la version void * , à l’exception de celle construite spécifiquement pour violer cela.

Néanmoins, chaque programmeur qui utilise uintptr_t s’attend uintptr_t ce que le résultat identifie complètement le pointeur d’origine (il contient toutes les informations à reconvertir en pointeur d’origine) et s’attend donc à ce que le résultat de uintptr_t diffère de celui de tous les pointeurs différents.

En ce qui concerne un exemple spécifique, le cadre Accelerate de macOS s’attend à ce que la conversion de pointeurs différents en uintptr_t produise des résultats différents, et je suis convaincu que de nombreuses autres parties de macOS le font également.