web-dev-qa-db-fra.com

erreur: cast de 'void *' à 'int' perd de la précision

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?

58
Joshua D. Boyd

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.

61
Ferruccio

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.

27
onlooker

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.

11
AnT

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.

8
Joshua D. Boyd

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.

7
Martin York

au lieu d'utiliser un long casting, vous devriez lancer cast_size_t.

int val = (int) ((size_t) arg);

4
Georg

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*.

3
AraK

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.

2

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.

2
MKaama

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.

1
siddhusingh

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.

1
Akos Hamori

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.

1
sbi

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);
0
Relio

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);
0
stefaanv

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.

0
Artelius

Un pointeur de fonction est incompatible avec void * (et tout autre pointeur non fonction)

0
user2249683
//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

0
Pieces