La conversion d'un pointeur sur un entier
Je suis en train d'adapter un code existant sur un ordinateur 64 bits. Le principal problème est que dans une fonction, la précédente codeur utilise un void* argument qui est converti dans le type adapté à 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 un ordinateur 64 bits, j'obtiens l'erreur:
error: cast from 'void*' to 'int' loses precision
Je voudrais corriger ce afin qu'il fonctionne encore sur un ordinateur 32 bits et aussi proprement que possible. Une idée ?
- Je sais que c'est déterrer un vieux post, mais il semble que l'on a accepté la réponse n'est pas tout à fait correct. Un exemple concret de
size_t
pas de travail est i386 segmentation de la mémoire. Si une machine 32 bits,sizeof
retourne2
poursize_t
. Alex réponse ci-dessous s'affiche correctement. Alex réponse etuintptr_t
fonctionne à peu près partout, et sa maintenant la norme. Il fournit un de C++11) de traitement, et il donne même le C++03-tête des gardes.
Vous devez vous connecter pour publier un commentaire.
Utilisation
intptr_t
etuintptr_t
.Pour s'assurer qu'il est défini de façon portable, vous pouvez utiliser le code comme ceci:
Juste place que dans certains .h de fichiers et d'inclure partout où vous en avez besoin.
Alternativement, vous pouvez télécharger la version de Microsoft de la
stdint.h
fichier de http://msinttypes.googlecode.com/svn/trunk/stdint.h" >ici ou utiliser un portable à l'un de http://www.azillionmonkeys.com/qed/pstdint.h" >ici.<cstdint>
, ou pour télécharger le boncstdint
si vous téléchargez unestdint.h
.cstdint
est une partie de la norme C++, comme le sont tous les noms de type y sont définies. Il est tout à fait approprié pour les balises spécifiées. ...Je ne suis en désaccord avec la définition des types manuellement, mais il peut être nécessaire lorsque l'on travaille avec des compilateurs qui ne le font pas.Je dirais que c'est du C++ moderne façon.
MODIFIER:
Le bon type de l'Entier
donc la bonne façon de stocker un pointeur d'entier est d'utiliser le
uintptr_t
ouintptr_t
types. (Voir aussi dans cppreference les types integer pour C99).ces types sont définis dans
<stdint.h>
pour le C99 et dans l'espace de nomsstd
pour le C++11 dans<cstdint>
(voir les types integer pour le C++).C++11 (à partir de) Version
C++03 Version
C99 Version
Le bon opérateur de coulée
En C il y a une seule fonte et à l'aide de la C cast en C++, c'est mal vu (donc ne pas l'utiliser en C++). En C++ il y a différentes distributions.
reinterpret_cast
est le bon casting pour cette conversion (Voir aussi ici).C++11 Version
C++03 Version
C Version
Questions Liées
uintptr_t
au lieu desize_t
, alors pourquoi demande-t-ilreinterpret_cast
? Il semble comme un simplestatic_cast
doit le faire étant donné que la norme prévoit spécifiquement les types de données compatibles...static_cast
peut convertir le type ou si c'est un pointeur peut ne pointeur ajustements si le type en a besoin.reinterpret_cast
est vraiment juste de changer le type de la sous-jacentes de la mémoire de modèle (pas de mutations). pour clarifier:static_cast
ne se comportent à l'identique ici.'size_t" et "ptrdiff_t" sont nécessaires pour correspondre à votre architecture (quel qu'il soit). Donc, je pense que plutôt que d'utiliser des 'int', vous devriez être en mesure d'utiliser la "size_t", qui sur un système 64 bits devrait être une version 64 bits de type.
Cette discussion unsigned int vs size_t va dans un peu plus en détail.
size_t
.size_t
est qu'il doit contenir le résultat de toutsizeof()
. Ce n'est pas nécessairement 64 bits x64. voir aussisize_t
peut en toute sécurité stocker la valeur d'un non-membre de pointeur. Voir en.cppreference.com/w/cpp/types/size_t.Utilisation
uintptr_t
que votre type entier.Plusieurs réponses ont rappelé
uintptr_t
et#include <stdint.h>
comme " la " solution. C'est, je pense, une partie de la réponse, mais pas toute la réponse. Vous avez aussi besoin de regarder là où la fonction est appelée avec l'ID de message de TOTO.Considérer ce code et de compilation:
Vous allez observer qu'il y a un problème à l'appel de l'emplacement (
main()
) — la conversion d'un entier à un pointeur sans un plâtre. Vous allez avoir besoin d'analyser votrefunction()
dans tous ses usages à voir comment les valeurs sont transmises. Le code à l'intérieur de monfunction()
si les appels ont été écrits:Depuis les vôtres sont probablement écrit différemment, vous devez examiner les points où la fonction est appelée pour s'assurer qu'il est logique d'utiliser la valeur. N'oubliez pas, vous pouvez peut-être trouver un latente bug.
Aussi, si vous allez à format de la valeur de la
void *
paramètre (conversion), regardez attentivement les<inttypes.h>
en-tête (au lieu destdint.h
—inttypes.h
fournit les services destdint.h
, ce qui est inhabituel, mais le standard C99 dit [t]il en-tête<inttypes.h>
inclut l'en-tête<stdint.h>
et l'étend avecles installations supplémentaires fournis par hébergés implémentations) et l'utilisation de la PRIxxx macros dans vos chaînes de format.
Aussi, mes commentaires sont strictement applicable à C au lieu de C++, mais votre code est dans le sous-ensemble de C++ qui est portable entre le C et le C++. Les chances sont juste à la bonne que mes commentaires s'appliquent.
#include <stdint.h>
uintptr_t
type standard défini dans la norme en-tête de fichier.Je pense que le "sens" de void* dans ce cas est un générique de la poignée.
Il n'est pas un pointeur vers une valeur, c'est la valeur elle-même.
(C'est juste la façon dont void* est utilisé en C et C++ pour les programmeurs.)
Si elle est maintenant une valeur de type entier, il vaut mieux être à l'intérieur d'intervalle entier!
Ici est facile de rendu en entier:
Il ne doit donner un avertissement.
Je suis tombé sur cette question, tout en étudiant le code source de SQLite.
Dans le sqliteInt.h, il y a un paragraphe de code défini une macro convertir entre entier et pointeur. L'auteur a fait un très bon exposé soulignant d'abord il faut un compilateur dépendante du problème et de mettre en œuvre la solution de compte pour les plus populaires, les compilateurs là-bas.
Et voici une citation du commentaire pour plus de détails:
Le crédit va à la committers.
La meilleure chose à faire est d'éviter la conversion de pointeur de type non-types de pointeur.
Cependant, ce n'est clairement pas possible dans votre cas.
Comme tout le monde le dit, le uintptr_t que vous devriez utiliser.
Ce lien a de bonnes infos sur la conversion de code 64 bits.
Il est également une bonne discussion sur comp.std.c
Depuis
uintptr_t
est de ne pas être là en C++/C++11, si c'est un chemin de conversion, vous pouvez envisageruintmax_t
, toujours défini dans<cstdint>
.De jouer en toute sécurité, on peut ajouter n'importe où dans le code d'une assertion: