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'affairevoid*
et intptr_t
nécessite des transtypages, donc aucun avantage icivoid*
signifie des conversions moins explicites lors du stockage de pointeurs, intptr_t
signifie moins de transtypages lors du stockage de valeurs entièresintptr_t
nécessite C99Que dois-je prendre d'autre en considération?
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 devoid*
?
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.
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.