100

既存のコードを 64 ビット マシンに適合させようとしています。主な問題は、ある関数で、前のコーダーが void* 引数を使用し、関数自体で適切な型に変換されることです。簡単な例:

void function(MESSAGE_ID id, void* param)
{
    if(id == FOO) {
        int real_param = (int)param;
        // ...
    }
}

もちろん、64 ビット マシンでは次のエラーが表示されます。

error: cast from 'void*' to 'int' loses precision

これを修正して、32 ビット マシンでもできるだけきれいに動作するようにしたいと思います。何か案が ?

4

11 に答える 11

115

これが最新の C++ の方法だと思います。

#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);

編集

Integer の正しい型

したがって、ポインターを整数として格納する正しい方法は、uintptr_torintptr_t型を使用することです。( C99 の cppreference整数型も参照してください)。

これらの型は<stdint.h>、C99 では で、stdC++11 では名前空間で定義されています (C++の整数型を<cstdint>参照してください)。

C++11 (およびそれ以降) のバージョン

#include <cstdint>
std::uintptr_t i;

C++03 バージョン

extern "C" {
#include <stdint.h>
}

uintptr_t i;

C99 バージョン

#include <stdint.h>
uintptr_t i;

正しいキャスト演算子

C には 1 つのキャストしかなく、C++ で C キャストを使用することは嫌われます (したがって、C++ では使用しないでください)。C++ にはさまざまなタイプのキャストがreinterpret_castありますが、この変換の正しいキャストです (こちらも参照)。

C++11 バージョン

auto i = reinterpret_cast<std::uintptr_t>(p);

C++03 バージョン

uintptr_t i = reinterpret_cast<uintptr_t>(p);

C バージョン

uintptr_t i = (uintptr_t)p; // C Version

関連する質問

于 2014-10-27T11:07:40.543 に答える
73

とを使用intptr_tuintptr_tます。

移植可能な方法で定義されていることを確認するには、次のようなコードを使用できます。

#if defined(__BORLANDC__)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
    typedef unsigned long uintptr_t;
#elif defined(_MSC_VER)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
#else
    #include <stdint.h>
#endif

それをいくつかの .h ファイルに配置し、必要な場所に含めるだけです。

または、ここからMicrosoft のバージョンのstdint.hファイルをダウンロードするか、ここからポータブル ファイルを使用することもできます。

于 2008-09-30T13:45:34.987 に答える
43

「size_t」と「ptrdiff_t」は、アーキテクチャに一致させるために必要です (それが何であれ)。したがって、「int」を使用するのではなく、64 ビット システムでは 64 ビット型である「size_t」を使用できるはずです。

このunsigned int と size_tの議論では、もう少し詳しく説明します。

于 2008-09-30T15:05:50.503 に答える
16

uintptr_t整数型として使用します。

于 2008-09-30T13:46:37.697 に答える
8

いくつかの回答は、「その」ソリューションとして指摘さuintptr_tれています。#include <stdint.h>つまり、答えの一部ではありますが、答え全体ではありません。FOO のメッセージ ID で関数が呼び出された場所も確認する必要があります。

次のコードとコンパイルを検討してください。

$ cat kk.c
#include <stdio.h>
static void function(int n, void *p)
{
    unsigned long z = *(unsigned long *)p;
    printf("%d - %lu\n", n, z);
}

int main(void)
{
    function(1, 2);
    return(0);
}
$ rmk kk
        gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith \
            -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
            -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE kk.c -o kk 
kk.c: In function 'main':
kk.c:10: warning: passing argument 2 of 'func' makes pointer from integer without a cast
$

呼び出し位置 ( ) に問題があることがわかりますmain()— キャストなしで整数をポインターに変換します。function()値がどのように渡されるかを確認するには、すべての使用法を分析する必要があります。function()呼び出しが記述されている場合、my 内のコードは機能します。

unsigned long i = 0x2341;
function(1, &i);

あなたのものはおそらく異なって書かれているので、示されているように値を使用することが理にかなっていることを確認するために、関数が呼び出されるポイントを確認する必要があります. 潜在的なバグを見つけている可能性があることを忘れないでください。

また、パラメータの値を (変換されたように) フォーマットする場合はvoid *、ヘッダーを注意深く見てください<inttypes.h>(代わりにstdint.hinttypes.hのサービスを提供しますstdint.h。これは珍しいことですが、C99 標準では、[t]ヘッダー<inttypes.h>にはヘッダー<stdint.h>とヘッダーが含まれていると記載されています)。ホストされた実装によって提供される追加機能で拡張し、フォーマット文字列で PRIxxx マクロを使用します。

また、私のコメントは C++ ではなく C に厳密に適用されますが、コードは C と C++ の間で移植可能な C++ のサブセットです。私のコメントが当てはまる可能性はかなり高いです。

于 2008-09-30T14:20:32.467 に答える
4
  1. #include <stdint.h>
  2. uintptr_tインクルードされた標準ヘッダー ファイルで定義されている標準型を使用します。
于 2010-11-10T11:23:50.250 に答える
2

この場合の void* の「意味」は汎用ハンドルだと思います。これは値へのポインタではなく、値そのものです。(これはたまたま、C および C++ プログラマーが void* を使用する方法です。)

整数値を保持している場合は、整数の範囲内にある方がよいでしょう!

整数への簡単なレンダリングは次のとおりです。

int x = (char*)p - (char*)0;

警告のみを表示する必要があります。

于 2011-11-10T06:21:15.280 に答える
2

最善の方法は、ポインター型から非ポインター型への変換を避けることです。ただし、これは明らかにあなたのケースでは不可能です。

誰もが言ったように、uintptr_t を使用する必要があります。

このリンクには、64 ビット コードへの変換に関する適切な情報があります。

comp.std.cにもこれに関する良い議論があります

于 2008-09-30T14:05:07.247 に答える