112 votes

Convertir un pointeur en un entier

Je suis en train d'essayer d'adapter un code existant pour une machine 64 bits. Le principal problème est que dans une fonction, le codeur précédent utilise un argument void* qui est converti en type approprié dans la fonction elle-même. Un court exemple:

void function(MESSAGE_ID id, void* param)
{
    if(id == FOO) {
        int real_param = (int)param;
        // ...
    }
}

Bien sûr, sur une machine 64 bits, j'obtiens l'erreur:

erreur: la conversion de 'void*' en 'int' perd de la précision

Je voudrais corriger cela pour que cela fonctionne toujours sur une machine 32 bits et aussi proprement que possible. Des idées ?

5 votes

Je sais que cela ressuscite un ancien post, mais il semble que la réponse acceptée ne soit pas tout à fait correcte. Un exemple concret de size_t ne fonctionnant pas est la mémoire segmentée i386. Bien qu'il s'agisse d'une machine 32 bits, sizeof retourne 2 pour size_t. La réponse de Alex ci-dessous semble correcte. La réponse d'Alex et uintptr_t fonctionnent presque partout et c'est désormais standard. Il offre un traitement C++11, et il donne même les protections de l'en-tête C++03.

73voto

Milan Babuškov Points 20423

Utilisez intptr_t et uintptr_t.

Pour vous assurer qu'il est défini de manière portable, vous pouvez utiliser du code comme celui-ci :

#if defined(__BORLANDC__)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
    typedef unsigned long uintptr_t;
#elif defined(_MSC_VER)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
#else
    #include 
#endif

Placez simplement cela dans un fichier .h et incluez-le partout où vous en avez besoin.

Alternativement, vous pouvez télécharger la version de Microsoft du fichier stdint.h depuis ici ou utiliser une version portable depuis ici.

0 votes

Voir stackoverflow.com/questions/126279/… pour des informations sur la façon d'obtenir un stdint.h qui fonctionne avec MSVC (et éventuellement Borland).

3 votes

Les deux liens sont cassés!

2 votes

Cette réponse est liée à C mais le langage est balisé C++ donc ce n'est pas la réponse que je cherchais.

42voto

Richard Corden Points 12292

'size_t' et 'ptrdiff_t' doivent correspondre à votre architecture (quelle qu'elle soit). Par conséquent, je pense qu'au lieu d'utiliser 'int', vous devriez pouvoir utiliser 'size_t', qui sur un système 64 bits devrait être un type de 64 bits.

Cette discussion unsigned int vs size_t va un peu plus en détail.

37 votes

Alors que size_t est généralement assez grand pour contenir un pointeur, ce n'est pas nécessairement le cas. Il serait préférable de localiser un en-tête stdint.h (si votre compilateur ne l'a pas déjà) et d'utiliser uintptr_t.

3 votes

Malheureusement, la seule contrainte sur size_t est qu'elle doit contenir le résultat de n'importe quel sizeof(). Cela ne le rend pas nécessairement sur 64 bits sur x64. voir aussi

3 votes

size_t peut stocker en toute sécurité la valeur d'un pointeur non membre. Voir en.cppreference.com/w/cpp/types/size_t.

17voto

moonshadow Points 28302

Utilisez uintptr_t comme type d'entier.

9voto

Jonathan Leffler Points 299946

Plusieurs réponses ont pointé vers uintptr_t et #include comme étant 'la' solution. C'est, je suggère, une partie de la réponse, mais pas toute la réponse. Vous devez également examiner l'endroit où la fonction est appelée avec l'ID de message de FOO.

Considérez ce code et cette compilation :

$ cat kk.c
#include 
static void function(int n, void *p)
{
    unsigned long z = *(unsigned long *)p;
    printf("%d - %lu\n", n, z);
}

int main(void)
{
    function(1, 2);
    return(0);
}
$ rmk kk
        gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith \
            -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
            -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE kk.c -o kk 
kk.c: In function 'main':
kk.c:10: warning: passing argument 2 of 'func' makes pointer from integer without a cast
$

Vous observerez qu'il y a un problème à l'emplacement de l'appel (dans main()) — convertir un entier en pointeur sans cast. Vous devrez analyser votre function() dans toutes ses utilisations pour voir comment les valeurs lui sont passées. Le code à l'intérieur de ma function() fonctionnerait si les appels étaient écrits :

unsigned long i = 0x2341;
function(1, &i);

Comme les vôtres sont probablement écrits différemment, vous devez examiner les points où la fonction est appelée pour vous assurer qu'il est logique d'utiliser la valeur comme indiqué. N'oubliez pas, vous pourriez trouver un bug latent.

De plus, si vous souhaitez formater la valeur du paramètre void * (une fois convertie), regardez attentivement l'en-tête (au lieu de stdint.hinttypes.h fournit les services de stdint.h, ce qui est inhabituel, mais la norme C99 dit que [t]he header includes the header and extends it with additional facilities provided by hosted implementations) et utilisez les macros PRIxxx dans vos chaînes de format.

En outre, mes commentaires s'appliquent strictement au C plutôt qu'au C++, mais votre code fait partie du sous-ensemble de C++ qui est portable entre C et C++. Il est fort probable que mes commentaires s'appliquent.

3 votes

Je pense que vous avez manqué le point de ma question. Le code stocke la valeur d'un entier dans un pointeur. Et cette partie du code fait l'opposé (par exemple, extrait la valeur de l'entier qui a été écrit comme un pointeur)

0 votes

@PierreBdR Néanmoins, il soulève un point très valide. Ce n'est pas toujours aussi simple de regarder le code (même lorsque les compilateurs avertissent à ce sujet) qui utilise un int signé mais qui est utilisé pour une taille et de penser qu'il est correct de le changer en unsigned. Malheureusement, ce n'est pas toujours aussi simple. Vous devez examiner chaque cas de manière explicite, à moins que vous ne vouliez provoquer des bugs potentiels - et des bugs subtiles en plus.

4voto

Fahrenheit2539 Points 1809

Plus d'informations sur size_t et ptrdiff_t peuvent être trouvées dans cet article: http://www.viva64.com/en/a/0050/. En parlant de problèmes de portabilité, il est plutôt facile de détecter celui-ci. Pour découvrir plus de problèmes cachés, je suggère d'exécuter une analyse statique (ces gars fournissent l'outil spécifiquement pour les problèmes 64 bits, une version d'essai est disponible ici: http://pvs-studio.viva64.com

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X