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
これをキャストする適切な方法は何ですか?
intptr_t
型にキャストできます。 int
型は、ポインターを含むのに十分な大きさであることが保証されています。 #include <cstdint>
を使用して定義します。
繰り返しますが、上記の答えはすべて、ポイントをひどく逃しました。 OPはポインター値をint値に変換したかったのですが、代わりに、ほとんどの答えはいずれにせよ、argポイントの内容を誤ってint値に変換しようとしました。そして、これらのほとんどはgcc4でも動作しません。
正解は、データの精度を失うことを気にしない場合、
int x = *((int*)(&arg));
これはGCC4で機能します。
最善の方法は、可能であれば、そのようなキャストを行わず、代わりにポインターとint(RAMの保存など)で同じメモリアドレスを共有する必要がある場合、ユニオンを使用し、memアドレスが処理される場合intとして最後に設定されたことがわかっている場合にのみ、intとして。
一般的な場合、これをint
にキャストする適切な方法はありません。 C99標準ライブラリはintptr_t
およびuintptr_t
typedef。これは、そのようなキャストを実行する必要が生じたときに使用されることになっています。標準ライブラリ(C99でなくても)でこれらのタイプが提供される場合は、それらを使用してください。そうでない場合は、プラットフォームのポインタサイズを確認し、これらのtypedefを自分で定義して使用してください。
の代わりに:
int x = (int)arg;
つかいます:
int x = (long)arg;
ほとんどのプラットフォームでは、ポインターとlongは同じサイズですが、64ビットプラットフォームではintとポインターが同じサイズではないことがよくあります。 (void*
)から(long
)に精度は失われません。次に、(long
)を(int
)に割り当てることで、適切に数値を切り捨てます。
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 *に変換し、再び戻すことは(どこでも)十分にサポートされています。
したがって、結果として、動的にポインターを生成し、それを使用する傾向があります。リークしないように、使用後にポインタを削除することを忘れないでください。
ロングキャストを使用する代わりに、size_tにキャストする必要があります。
int val =(int)((size_t)arg);
適切な方法は、別のpointer type
にキャストすることです。 void*
をint
に変換することは、機能する場合と機能しない場合がある移植性のない方法です。返されたアドレスを保持する必要がある場合は、void*
として保持してください。
私もこの問題に直面しています。
ids [i] =(int)arg; //ここでエラーが発生しました=>これを以下に変更します。
ids [i] =(uintptr_t)arg;
その後、コンパイルを続行できます。たぶん、あなたもこれを試すことができます。
64ビットポインターを32ビット整数に格納する「正しい」方法はありません。問題はキャストではなく、ポインターの半分を失うターゲットタイプにあります。 int
内に保存されている残りの32ビットは、スレッド関数へのポインターを再構築するには不十分です。ほとんどの答えは、引数から32個の無駄なビットを抽出しようとするだけです。
Ferruccio のように、プログラムを意味のあるものにするには、intをintptr_t
に置き換える必要があります。
最も安全な方法:
static_cast<int>(reinterpret_cast<long>(void * your_variable));
long
は、任意のマシン上のLinuxでのポインターサイズを保証します。 Windowsは、64ビットでも32ビット長です。したがって、64ビットのウィンドウでは、long
ではなくlong long
に変更する必要があります。したがって、reinterpret_cast
はlong
型にキャストし、static_cast
は安全にlong
をint
にキャストします(データを切り捨てる準備ができている場合)。
構造体を作成し、それを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が存在することに注意してください。
このようなスレッド作成関数を呼び出す場合
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)
を前提としています。コードが、これが成り立たないプラットフォームに移植される可能性がある場合、これは機能しません。
私の場合、バッファへのオフセットを表す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);
Intをvoid*
として渡さないで、int*
をint
に渡してください。そうすれば、void*
をint*
にキャストして、 int
への逆参照ポインタ。
int x = *static_cast<int*>(arg);
あなたが望むのは
int x = reinterpret_cast<int>(arg);
これにより、void *
をint
として再解釈できます。
関数ポインターはvoid *(およびその他の非関数ポインター)と互換性がありません
//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;
お役に立てれば