sizeof (int) == sizeof (void *)?

Existe-t-il un type entier de même taille que le pointeur? Garanti sur toutes les microarchitectures?

    Selon cette page Wikipedia , dans l’en-tête C99, votre en-tête stdint.h peut déclarer intptr_t et uintptr_t, mais cela nécessite bien entendu

    • C99
    • Un implémenteur de compilateur qui a choisi d’implémenter cette partie optionnelle de la norme

    Donc, en général, je pense que celui-ci est difficile.

    En termes simples, non. Non garanti sur toutes les architectures.

    Ma question est: pourquoi? Si vous voulez affecter un type assez grand pour stocker un void* , la meilleure chose à faire est d’allouer (assez étonnamment 🙂 un void* . Pourquoi est-il nécessaire de l’intégrer dans un int ?

    MODIFIER: en fonction des commentaires que vous avez formulés sur votre question dupliquée, vous souhaitez stocker des valeurs spéciales du pointeur (1, 2, 3) pour indiquer des informations supplémentaires.

    NON!! Ne fais pas ça !! . Il n’y a aucune garantie que 1, 2 et 3 ne soient pas des indicateurs parfaitement valides. C’est peut-être le cas dans les systèmes où vous devez aligner les pointeurs sur des limites de 4 octets, mais puisque vous avez posé des questions sur toutes les architectures, je suppose que la portabilité est une valeur élevée.

    Trouvez une autre façon de le faire qui soit correcte. Par exemple, utilisez l’union (la syntaxe à partir de la mémoire peut être fausse):

     typedef struct { int isPointer; union { int intVal; void *ptrVal; } } myType; 

    Ensuite, vous pouvez utiliser le “booléen” isPointer pour décider si vous devez traiter l’union comme un entier ou un pointeur.

    MODIFIER:

    Si la rapidité d’exécution est primordiale, la solution typedef est la solution. Fondamentalement, vous devrez définir le nombre entier souhaité pour chaque plate-forme sur laquelle vous souhaitez exécuter. Vous pouvez le faire avec une compilation conditionnelle. J’appendais également une vérification d’exécution afin de vous assurer que vous avez correctement compilé pour chaque plate-forme (je la définis dans le source mais vous transmetsortingez cela en tant cc -DPTRINT_INT compilateur, comme ” cc -DPTRINT_INT “):

     #include  #define PTRINT_SHORT #ifdef PTRINT_SHORT typedef short psortingnt; #endif #ifdef PTRINT_INT typedef int psortingnt; #endif #ifdef PTRINT_LONG typedef long psortingnt; #endif #ifdef PTRINT_LONGLONG typedef long long psortingnt; #endif int main(void) { if (sizeof(psortingnt) != sizeof(void*)) { printf ("ERROR: psortingnt doesn't match void* for this platform.\n"); printf (" sizeof(void* ) = %d\n", sizeof(void*)); printf (" sizeof(psortingnt ) = %d\n", sizeof(psortingnt)); printf (" =================\n"); printf (" sizeof(void* ) = %d\n", sizeof(void*)); printf (" sizeof(short ) = %d\n", sizeof(short)); printf (" sizeof(int ) = %d\n", sizeof(int)); printf (" sizeof(long ) = %d\n", sizeof(long)); printf (" sizeof(long long) = %d\n", sizeof(long long)); return 1; } /* rest of your code here */ return 0; } 

    Sur mon système (Ubuntu 8.04, 32 bits), je reçois:

     ERROR: psortingnt typedef doesn't match void* for this platform. sizeof(void* ) = 4 sizeof(psortingnt ) = 2 ================= sizeof(short ) = 2 sizeof(int ) = 4 sizeof(long ) = 4 sizeof(long long) = 8 

    Dans ce cas, je saurais que j’ai besoin de comstackr avec PTRINT_INT (ou long). Il y a peut-être un moyen de résoudre ce problème au moment de la compilation avec #if, mais je ne pouvais pas être dérangé pour le rechercher pour le moment. Si vous frappez une plate-forme où il n’y a pas de type entier suffisant pour contenir un pointeur, vous avez de la chance.

    N’oubliez pas que l’utilisation de valeurs de pointeur spéciales (1, 2, 3) pour représenter des entiers peut également ne pas fonctionner sur toutes les plates-formes; il peut en réalité s’agir d’adresses de mémoire valides pour les pointeurs.

    Néanmoins, si vous ignorez mon conseil, je ne peux rien faire pour vous arrêter. C’est votre code après tout :-). Une possibilité consiste à vérifier toutes les valeurs de retour de malloc et, si vous obtenez 1, 2 ou 3, remettez-vous simplement dans malloc (c.-à-d. Utilisez un mymalloc () qui le fait automatiquement). Ce sera une fuite de mémoire mineure, mais cela ne garantira aucun conflit entre vos pointeurs spéciaux et les pointeurs réels.

    La norme C99 définit les types standard int:

    7.18.1.4 Types entiers capables de contenir des pointeurs d’object Le type suivant désigne un type entier signé avec la propriété selon laquelle tout pointeur valide sur void peut être converti en ce type, puis reconverti en pointeur à vide, et le résultat sera comparable à la valeur pointeur d’origine:

      intptr_t 

    Le type suivant désigne un type entier non signé avec la propriété selon laquelle tout pointeur valide sur void peut être converti en ce type, puis reconverti en pointeur à vide, et le résultat sera comparable au pointeur d’origine:

      uintptr_t 

    Ces types sont optionnels.

    C99 définit également size_t et ptrdiff_t:

    Les types sont

      ptrdiff_t 

    qui est le type entier signé du résultat de la soustraction de deux pointeurs;

      size_t 

    qui est le type entier non signé du résultat de l’opérateur sizeof; et

    Les architectures que j’ai vues ont la taille maximale d’un object égale à l’ensemble de la mémoire, donc sizeof (size_t) == sizeof (void *), mais je ne suis au courant d’aucun élément portable à la fois vers C89 ( size_t ) et garanti suffisamment grand (ce qui est uintptr_t ).

    Ce serait vrai sur un système 32 bits standard, mais il n’y a certainement aucune garantie, et vous pourriez trouver beaucoup d’architectures où ce n’est pas vrai. Par exemple, une idée fausse commune est que sizeof (int) sur x86_64 serait 8 (puisqu’il s’agit d’un système 64 bits, je suppose), ce qui n’est pas le cas. Sur x86_64, sizeof (int) est toujours 4, mais sizeof (void *) est 8.

    Alors que dire de C ++. Dois-je aller jusqu’au bout de:

     template  struct int_traits_t; template <> struct int_traits_t <16> {typedef uint16_t int_t;}; template <> struct int_traits_t <32> {typedef uint32_t int_t;}; template <> struct int_traits_t <64> {typedef uint64_t int_t;}; typedef int_traits_t ::int_t myintptr_t; 

    juste pour obtenir un entier portable de la taille du pointeur?

    La solution standard à ce problème consiste à écrire un petit programme qui vérifie la taille de tous les types int (short int, int, long int) et les compare à void *. S’il y a une correspondance, il émet un morceau de code qui définit le type intptr. Vous pouvez mettre cela dans un fichier d’en-tête et utiliser le nouveau type.

    Il est simple d’inclure ce code dans le processus de construction (en utilisant make , par exemple)

    Non, le plus proche d’un type entier portable capable de pointer serait intptr_t et ptrdiff_t .

    Non.

    Je ne crois pas que la norme C spécifie même les tailles standard int . Combinez cela avec toutes les architectures existantes (8/16/32/64 bits, etc.) et il n’y a aucun moyen de garantir quoi que ce soit.

    int type de données serait la réponse sur la plupart des architectures.

    Mais il n’ya AUCUNE garantie de le faire pour TOUT architecture (micro).

    La réponse semble être “non”, mais si tout ce dont vous avez besoin est un type pouvant agir à la fois, vous pouvez utiliser une union:

     union int_ptr_t { int i; void* p; }; 

    En général, sizeof (* void) dépend de la largeur du bus de mémoire (bien que ce ne soit pas nécessairement le cas. L’AS / 400 antérieur à RISC disposait d’un bus d’adresse de 48 bits mais de pointeurs de 64 bits). exceptions également – SGI C utilisait des ints 32 bits sur des MIPS 64 bits).

    Donc, il n’y a aucune garantie.