J'ai une fonction avec le prototype void* myFcn(void* arg)
qui est utilisée comme point de départ pour un pthread. J'ai besoin de convertir l'argument en int pour un usage ultérieur:
int x = (int)arg;
Le compilateur (GCC version 4.2.4) renvoie l'erreur:
file.cpp:233: error: cast from 'void*' to 'int' loses precision
Quelle est la bonne façon de lancer ceci?
Vous pouvez le lancer sur un intptr_t
type. C'est un type int
garanti d'être assez grand pour contenir un pointeur. Utilisation #include <cstdint>
pour le définir.
Encore une fois, toutes les réponses ci-dessus ont mal compris. L'OP souhaitait convertir une valeur de pointeur en une valeur int. La plupart des réponses, d'une manière ou d'une autre, tentaient de convertir à tort le contenu des points arg en une valeur int. Et, la plupart d’entre eux ne fonctionneront même pas sur gcc4.
La bonne réponse est, si cela ne vous gêne pas de perdre la précision des données,
int x = *((int*)(&arg));
Cela fonctionne sur GCC4.
Le meilleur moyen est, si possible, de ne pas faire une telle conversion, mais si la même adresse mémoire doit être partagée pour le pointeur et l'int (par exemple, pour économiser de la RAM), utilisez union et assurez-vous que l'adresse mem est traitée comme int seulement si vous savez qu'il a été défini en dernier comme int.
Il n'y a pas de moyen approprié de convertir ceci en int
en général. La bibliothèque standard C99 fournit intptr_t
et uintptr_t
_ typedefs, qui sont supposés être utilisés chaque fois que le besoin de faire un tel casting se fait sentir. Si votre bibliothèque standard (même si ce n'est pas C99) fournit ces types, utilisez-les. Sinon, vérifiez la taille du pointeur sur votre plate-forme, définissez vous-même ces typedef et utilisez-les.
Au lieu de:
int x = (int)arg;
utilisation:
int x = (long)arg;
Sur la plupart des plates-formes, les pointeurs et les longs ont la même taille, mais les ints et les pointeurs ne sont souvent pas de la même taille sur les plates-formes 64 bits. Si vous convertissez (void*
) à (long
) aucune précision n'est perdue, puis en affectant le (long
) à un (int
), il tronque correctement le nombre à ajuster.
Lancer un pointeur sur void * et back est une utilisation valide de reinterpret_cast <>. Pour que vous puissiez faire ceci:
pthread_create(&thread, NULL, myFcn, new int(5)); // implicit cast to void* from int*
Puis dans myFcn:
void* myFcn(void* arg)
{
int* data = reinterpret_cast<int*>(arg);
int x = *data;
delete data;
Remarque: comme le fait remarquer sbi, cela nécessiterait une modification de l'appel OP pour créer le thread.
Ce que j'essaie de souligner que la conversion d'un point de vue int à un pointeur et vice-versa peut être source de problèmes lorsque vous passez d'une plateforme à l'autre. MAIS convertir un pointeur en vide * et vice versa est bien pris en charge (partout).
En conséquence, il peut être moins sujet aux erreurs de générer un pointeur de manière dynamique et de l'utiliser. N'oubliez pas de supprimer le pointeur après utilisation afin d'éviter toute fuite.
au lieu d'utiliser un long casting, vous devriez lancer cast_size_t.
int val = (int) ((size_t) arg);
La bonne façon est de le jeter à un autre pointer type
. Conversion d'un void*
à int
est une méthode non portable qui peut fonctionner ou non! Si vous devez conserver l'adresse renvoyée, conservez-la simplement comme void*
.
Je rencontre ce problème aussi.
ids [i] = (int) arg; // erreur se produit ici => Je change cela en bas.
ids [i] = (uintptr_t) arg;
Ensuite, je peux continuer à compiler. Peut-être que vous pouvez essayer cela aussi.
Il n'y a pas de manière "correcte" de stocker un pointeur 64 bits dans un entier 32 bits. Le problème ne vient pas de la diffusion, mais du type de cible qui perd la moitié du pointeur. Les 32 bits restants stockés dans int
ne suffisent pas pour reconstruire un pointeur sur la fonction thread. La plupart des réponses essaient simplement d'extraire 32 bits inutiles de l'argument.
Comme Ferruccio dit, int doit être remplacé par intptr_t
pour donner du sens au programme.
Manière la plus sûre:
static_cast<int>(reinterpret_cast<long>(void * your_variable));
long
garantit une taille de pointeur sous Linux sur n'importe quelle machine. Windows a également 32 bits de long uniquement sur 64 bits. Par conséquent, vous devez le changer en long long
au lieu de long
dans Windows pour 64 bits. Alors reinterpret_cast
l'a jeté dans long
puis tapez static_cast
transforme long
en toute sécurité _ vers int
, si vous êtes prêt à filtrer les données.
Je voudrais créer une structure et passer cela comme void * à pthread_create
struct threadArg {
int intData;
long longData;
etc...
};
threadArg thrArg;
thrArg.intData = 4;
...
pthread_create(&thread, NULL, myFcn, (void*)(threadArg*)&thrArg);
void* myFcn(void* arg)
{
threadArg* pThrArg = (threadArg*)arg;
int computeSomething = pThrArg->intData;
...
}
Gardez à l'esprit que thrArg devrait exister jusqu'à ce que myFcn () l'utilise.
Si vous appelez votre fonction de création de fil comme ceci
pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));
alors le void*
qui arrive à l'intérieur de myFcn
a la valeur du int
que vous y avez mis. Donc vous savez que vous pouvez le rejeter comme ça
int myData = reinterpret_cast<int>(arg);
même si le compilateur ne sait pas que vous ne transmettez jamais que myFcn
à pthread_create
en conjonction avec un entier.
Edit:
Comme l'a souligné Martin, cela suppose que sizeof(void*)>=sizeof(int)
. Si votre code a la chance d'être porté sur une plate-forme où cela ne fonctionne pas, cela ne fonctionnera pas.
Dans mon cas, j’utilisais une valeur 32 bits qui devait être transmise à une fonction OpenGL sous la forme d’un vide * représentant un décalage dans une mémoire tampon.
Vous ne pouvez pas simplement convertir la variable 32 bits en un pointeur, car ce pointeur sur une machine 64 bits est deux fois plus long. La moitié de votre pointeur sera des ordures. Vous devez passer un pointeur réel.
Cela vous donnera un pointeur à partir d'un décalage de 32 bits:
int32 nOffset = 762; // random offset
char * pOffset = NULL; // pointer to hold offset
pOffset += nOffset; // this will now hold the value of 762 correctly
glVertexAttribPointer(binding, nStep, glType, glTrueFalse, VertSize(), pOffset);
Ne passez pas votre int en tant que void*
, passe un int*
à votre int
, vous pouvez ainsi lancer le void*
à un int*
et copiez le pointeur déréférencé sur votre int
.
int x = *static_cast<int*>(arg);
Ce que vous voudrez peut-être, c'est
int x = reinterpret_cast<int>(arg);
Cela vous permet de réinterpréter le void *
comme int
.
Un pointeur de fonction est incompatible avec void * (et tout autre pointeur non fonction)
//new_fd is a int
pthread_create(&threads[threads_in_use] , NULL, accept_request, (void*)((long)new_fd));
//inside the method I then have
int client;
client = (long)new_fd;
J'espère que cela t'aides