web-dev-qa-db-ja.com

エラー: 'void *'から 'int'にキャストすると精度が失われます

Pthreadの開始点として使用されるプロトタイプvoid* myFcn(void* arg)を持つ関数があります。後で使用するために引数をintに変換する必要があります。

int x = (int)arg;

コンパイラー(GCCバージョン4.2.4)は次のエラーを返します。

file.cpp:233: error: cast from 'void*' to 'int' loses precision

これをキャストする適切な方法は何ですか?

58
Joshua D. Boyd

intptr_t型にキャストできます。 int型は、ポインターを含むのに十分な大きさであることが保証されています。 #include <cstdint>を使用して定義します。

61
Ferruccio

繰り返しますが、上記の答えはすべて、ポイントをひどく逃しました。 OPはポインター値をint値に変換したかったのですが、代わりに、ほとんどの答えはいずれにせよ、argポイントの内容を誤ってint値に変換しようとしました。そして、これらのほとんどはgcc4でも動作しません。

正解は、データの精度を失うことを気にしない場合、

int x = *((int*)(&arg));

これはGCC4で機能します。

最善の方法は、可能であれば、そのようなキャストを行わず、代わりにポインターとint(RAMの保存など)で同じメモリアドレスを共有する必要がある場合、ユニオンを使用し、memアドレスが処理される場合intとして最後に設定されたことがわかっている場合にのみ、intとして。

27
onlooker

一般的な場合、これをintにキャストする適切な方法はありません。 C99標準ライブラリはintptr_tおよびuintptr_t typedef。これは、そのようなキャストを実行する必要が生じたときに使用されることになっています。標準ライブラリ(C99でなくても)でこれらのタイプが提供される場合は、それらを使用してください。そうでない場合は、プラットフォームのポインタサイズを確認し、これらのtypedefを自分で定義して使用してください。

11
AnT

の代わりに:

int x = (int)arg;

つかいます:

int x = (long)arg;

ほとんどのプラットフォームでは、ポインターとlongは同じサイズですが、64ビットプラットフォームではintとポインターが同じサイズではないことがよくあります。 (void*)から(long)に精度は失われません。次に、(long)を(int)に割り当てることで、適切に数値を切り捨てます。

8
Joshua D. Boyd

Void *へのポインターのキャストとその逆は、reinterpret_cast <>の有効な使用です。だからあなたはこれを行うことができます:

pthread_create(&thread, NULL, myFcn, new int(5)); // implicit cast to void* from int*

次に、myFcnで:

void* myFcn(void* arg)
{
    int*  data = reinterpret_cast<int*>(arg);
    int   x    = *data;
    delete data;

注:sbiが指摘しているように、これにはスレッドを作成するためにOP呼び出しを変更する必要があります。

プラットフォームからプラットフォームへ移動する際に、intからポインターへの変換とその逆の変換では問題が発生する可能性があることを強調します。ただし、ポインターをvoid *に変換し、再び戻すことは(どこでも)十分にサポートされています。

したがって、結果として、動的にポインターを生成し、それを使用する傾向があります。リークしないように、使用後にポインタを削除することを忘れないでください。

7
Martin York

ロングキャストを使用する代わりに、size_tにキャストする必要があります。

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

4
Georg

適切な方法は、別のpointer typeにキャストすることです。 void*intに変換することは、機能する場合と機能しない場合がある移植性のない方法です。返されたアドレスを保持する必要がある場合は、void*として保持してください。

3
AraK

私もこの問題に直面しています。

ids [i] =(int)arg; //ここでエラーが発生しました=>これを以下に変更します。

ids [i] =(uintptr_t)arg;

その後、コンパイルを続行できます。たぶん、あなたもこれを試すことができます。

2

64ビットポインターを32ビット整数に格納する「正しい」方法はありません。問題はキャストではなく、ポインターの半分を失うターゲットタイプにあります。 int内に保存されている残りの32ビットは、スレッド関数へのポインターを再構築するには不十分です。ほとんどの答えは、引数から32個の無駄なビットを抽出しようとするだけです。

Ferruccio のように、プログラムを意味のあるものにするには、intをintptr_tに置き換える必要があります。

2
MKaama

最も安全な方法:

static_cast<int>(reinterpret_cast<long>(void * your_variable));

longは、任意のマシン上のLinuxでのポインターサイズを保証します。 Windowsは、64ビットでも32ビット長です。したがって、64ビットのウィンドウでは、longではなくlong longに変更する必要があります。したがって、reinterpret_castlong型にキャストし、static_castは安全にlongintにキャストします(データを切り捨てる準備ができている場合)。

1
siddhusingh

構造体を作成し、それを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;
    ...
}

myFcn()が使用するまで、thrArgが存在することに注意してください。

1
Akos Hamori

このようなスレッド作成関数を呼び出す場合

pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));

myFcnの内部に到着するvoid*は、そこに入れたintの値を持ちます。だからあなたはあなたがこのようにそれをキャストバックできることを知っています

int myData = reinterpret_cast<int>(arg);

コンパイラはmyFcnを整数と組み合わせてpthread_createに渡すことしか知らない場合でも。

編集

Martinが指摘したように、これはsizeof(void*)>=sizeof(int)を前提としています。コードが、これが成り立たないプラットフォームに移植される可能性がある場合、これは機能しません。

1
sbi

私の場合、バッファへのオフセットを表すvoid *としてOpenGL関数に渡す必要がある32ビット値を使用していました。

32ビット変数をポインターにキャストすることはできません。64ビットマシン上のポインターは2倍長いためです。ポインタの半分はゴミになります。実際のポインターを渡す必要があります。

これにより、32ビットオフセットからポインターが取得されます。

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

Intをvoid*として渡さないで、int*intに渡してください。そうすれば、void*int*にキャストして、 intへの逆参照ポインタ。

int x = *static_cast<int*>(arg);
0
stefaanv

あなたが望むのは

int x = reinterpret_cast<int>(arg);

これにより、void *intとして再解釈できます。

0
Artelius

関数ポインターはvoid *(およびその他の非関数ポインター)と互換性がありません

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;

お役に立てれば

0
Pieces