web-dev-qa-db-fra.com

Vous utilisez intptr_t au lieu de void *?

Est-ce une bonne idée d'utiliser intptr_t comme stockage général (pour contenir des pointeurs et des valeurs entières) au lieu de void*? (Comme vu ici: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html )

Pour ce que j'ai déjà lu:

  • int -> void* -> int l'aller-retour n'est pas garanti pour conserver la valeur d'origine; Je suppose que int -> intptr_t -> int fera l'affaire
  • pointeur arithmétique sur les deux void* et intptr_t nécessite des transtypages, donc aucun avantage ici
  • void* signifie des conversions moins explicites lors du stockage de pointeurs, intptr_t signifie moins de transtypages lors du stockage de valeurs entières
  • intptr_t nécessite C99

Que dois-je prendre d'autre en considération?

24
Gepard

Est-ce une bonne idée d'utiliser intptr_t Comme stockage à usage général (pour contenir des pointeurs et des valeurs entières) au lieu de void*?

Non.

intptr_t N'est pas garanti d'exister. Tout d'abord, comme vous le constatez, il a été introduit en C99. Deuxièmement, les implémentations ne doivent pas nécessairement avoir un type entier suffisamment grand pour contenir les valeurs de pointeur converties sans perte d'informations.

La conversion d'un int en intptr_t Et retour est peu probable de perdre des informations mais il n'y a aucune garantie réelle que intptr_t est plus large que int.

Si vous souhaitez stocker des valeurs de pointeur, stockez-les dans des objets de pointeur. C'est à cela que servent les objets pointeurs.

Tout pointeur vers un objet ou un type incomplet peut être converti en void* Et inversement sans perte d'informations. Il n'y a pas de telle garantie pour les pointeurs vers les fonctions - mais tout type de pointeur vers fonction peut être converti en n'importe quel autre type pointeur vers fonction et vice versa sans perte d'informations. (Je fais référence à la norme C; je pense que POSIX fournit des garanties supplémentaires.)

Si vous souhaitez stocker un entier ou une valeur de pointeur dans le même objet, la première chose à faire est de repenser votre conception. Si vous l'avez déjà fait et avez conclu que vous vouliez vraiment le faire, envisagez d'utiliser une union (et de suivre attentivement le type de valeur que vous avez stocké le plus récemment).

Il existe des API qui utilisent un argument void* Pour permettre la transmission de données arbitraires; voir, par exemple, la fonction POSIX pthread_create() . Cela peut être abusé en transtypant une valeur entière en void* Mais il est plus sûr de passer l'adresse d'un objet entier.

30
Keith Thompson

Non, vous ne pouvez pas être assuré qu'un type particulier est un moyen raisonnable de stocker à la fois des pointeurs et des entiers, et en plus, cela rend votre code déroutant. Il y a un meilleur moyen.

Si vous souhaitez stocker un entier et un pointeur dans le même objet, la méthode propre et portable consiste à utiliser une union:

union foo {
   int integer_foo;
   void *pointer_foo;
};

C'est portable et vous permet de stocker les deux types de choses dans la taille de stockage nécessaire pour le plus grand des deux. Il est garanti de toujours fonctionner.

5
Perry