J'ai une question concernant l'utilisation de intptr_t
Par rapport à long int
. J'ai observé que l'incrémentation des adresses mémoire (par exemple via l'arithmétique du pointeur manuel) diffère selon le type de données. Par exemple, l'incrémentation d'un pointeur char ajoute 1 à l'adresse mémoire, tandis que l'incrémentation d'un pointeur int ajoute 4, 8 pour un double, 16 pour un long double, etc.
Au début, j'ai fait quelque chose comme ça:
char myChar, *pChar;
float myFloat, *pFloat;
pChar = &myChar;
pFloat = &myFloat;
printf( "pChar: %d\n", ( int )pChar );
printf( "pFloat: %d\n", ( int )pFloat );
pChar++;
pFloat++;
printf( "and then after incrementing,:\n\n" );
printf( "pChar: %d\n", (int)pChar );
printf( "pFloat: %d\n", (int)pFloat );
qui a compilé et exécuté très bien, mais XCode m'a donné des avertissements pour mon transtypage: "Cast du pointeur vers un entier de taille différente."
Après quelques recherches sur Google et binging (ce dernier est-il encore un mot?), J'ai vu certaines personnes recommander d'utiliser intptr_t
:
#include <stdint.h>
...
printf( "pChar: %ld\n", ( intptr_t )pChar );
printf( "pFloat: %ld\n", ( intptr_t )pFloat );
ce qui résout en effet les erreurs. Donc, je pensais qu'à partir de maintenant, je devrais utiliser intptr_t
Pour les pointeurs de transtypage ... Mais après quelques agitations, j'ai trouvé que je pouvais résoudre le problème en remplaçant simplement int
par long int
:
printf( "pChar: %ld\n", ( long int )pChar );
printf( "pFloat: %ld\n", ( long int )pFloat );
Ma question est donc la suivante: pourquoi intptr_t
Est-il utile et quand doit-il être utilisé? Cela semble superflu dans ce cas. De toute évidence, les adresses mémoire de myChar
et myFloat
étaient tout simplement trop grandes pour tenir dans un int
... afin de les transtyper en long int
S ont résolu le problème .
Est-ce que les adresses mémoire sont parfois trop grandes pour long int
Aussi? Maintenant que j'y pense, je suppose que c'est possible si vous avez> 4 Go de RAM, auquel cas les adresses mémoire pourraient dépasser 2 ^ 32 - 1 (valeur maximale pour les entrées longues non signées ...) mais C a été créé bien avant imaginable, non? Ou étaient-ils aussi prémonitoires?
Merci!
Voici la chose: sur certaines plates-formes, int
est la bonne taille, mais sur d'autres, long
est la bonne taille. Comment savez-vous lequel est celui que vous devez utiliser? Non. On peut avoir raison, mais la norme ne garantit pas de laquelle il s'agirait (si c'est le cas). Ainsi, la norme fournit un type défini pour être de la bonne taille, quelle que soit la plateforme sur laquelle vous vous trouvez. Où auparavant vous deviez écrire:
#ifdef PLATFORM_A
typedef long intptr;
#else
typedef int intptr;
#endif
Maintenant, vous écrivez:
#include <stdint.h>
Et cela couvre tellement plus de cas. Imaginez spécialiser l'extrait ci-dessus pour chaque plate-forme unique votre code s'exécute.
intptr_t
est une nouvelle invention, créée après avoir imaginé des adresses mémoire 64 bits et même 128 bits.
Si vous jamais devez convertir un pointeur en un type entier, toujours utilisez intptr_t
. Faire autre chose entraînera des problèmes inutiles pour les personnes qui ont besoin de porter votre code à l'avenir.
Il a fallu beaucoup de temps pour résoudre tous les bogues avec cela dans des programmes comme Mozilla/Firefox lorsque les gens voulaient le compiler sur Linux 64 bits.
Premier, intptr_t
est uniquement destiné aux pointeurs de données (pas aux fonctions) et il n'est pas garanti d'exister.
Ensuite, non, vous ne devez pas l'utiliser pour l'impression. Le %p
est pour ça. Il vous suffit de lancer votre pointeur sur (void*)
et c'est parti.
Il n'est pas non plus utile pour l'arithmétique/l'accès aux octets individuels. Cast vers (unsigned char*)
au lieu.
intptr_t
est vraiment pour les rares occasions où vous devez interpréter les pointeurs comme des entiers (ce qu'ils ne sont vraiment pas). Ne fais pas ça si tu ne dois pas.
Vous pourriez vous faciliter la vie en utilisant le spécificateur de conversion p
:
printf("%p\n", (void *)foo);
De plus, la méthode portable pour imprimer une variable de type (u)intptr_t
consiste à utiliser le PRI*PTR
macros de inttypes.h
; ce qui suit équivaut à utiliser p
sur ma plateforme (32 bits):
printf("%08" PRIxPTR "\n", (uintptr_t)(void *)foo);
Les jets à void *
sont nécessaires pour une portabilité complète, mais peuvent être omis sur les plates-formes avec des représentations de pointeurs uniformes.