2011-02-07 8 views
0

また、キャストしないでください。私がやっていることは次のとおりです。C言語のvoid *を安全にintにキャストする方法はありますか?

Linuxデバイスドライバを上位レベルのライブラリにリンクするコードを書いています。ライブラリの作成者は、通信チャネルを記述する実装固有のオブジェクトにハンドルを格納するために、(typedefによって新しい名前で)を使用します。

ライブラリーと接続したいドライバーは、open()への呼び出しによって返されるファイル記述子であるため、intを使用してそのチャネルにハンドルを保管します。だから私のコードでは、void *がライブラリから渡され、intを使用してドライバからものを呼び出す必要があり、その逆もあります。 I.電子:

// somewhere in the library ... 
typedef void* CAN_HANDLE; 

// ... in my code 
CAN_HANDLE canOpen_driver(s_BOARD *board) 
{ 
    int fd; 
    // ... 
    fd = open(busname, O_RDWR); 
    // ... 
    return (CAN_HANDLE) fd; // <-- not safe, especially not when converting back. 
} 

他の人が実際に書かれているアダプタは、ポインタ間のキャストのどこかに、ちょうどいくつかの構造体などを保存するので、何のサイズの問題は生じません。私の場合は、OSが既にそうしているように、ファイル記述子を本当に管理したくありません。

私のPC上では、ポインタがintよりも大きいと思うので、私はこれを邪魔してしまうかもしれませんが、コードは組み込みシステムにも入ります。それらのマシン上のタイプのサイズに関する仮定。

+1

すべての大文字の「CAN_HANDLE」を見ると、私はLOLCODE memeの記憶に笑いかけました:)あなたのコードを批判しないでください... –

+0

ええ、私はあまりにも笑った。ライブラリはこれでいっぱいです:can_open、can_sendなど(CANバスライブラリです):) –

+1

'void *'は 'int'よりも小さくすることができますが、私はそれを見たことはないと確信しています。とにかく実際にはfdsは0から始まり、fd番号が大きすぎて 'void *'に格納することができない多くのfdsを作成する前にシステムリソースを使い果たします。これは違う方法ではできないと言っているわけではありませんが、個人的には無効なポインタ値を作成することをシステムがトラップしない限り、私はそれを見ていません。安全であるように、システムがfdsをサポートしているのと同じ数の文字を割り当てることができれば、その配列のn番目の要素へのポインタはfd nを表すことができ、fdごとの割り当てを避けることができます。 –

答えて

3

編集:もちろん、構造体は必要ありません。プレーンなintのメモリだけを割り当てることができます。

CAN_HANDLE canOpen_driver(s_BOARD *board) 
{ 
    int *fd = malloc(sizeof(int)); 
    if (fd) 
    { 
    // ... 
    *fd = open(busname, O_RDWR); 
    // ... 
    return (CAN_HANDLE) fd; 
    } 

    // failure 
    return NULL; 
} 

これは、クリーンアップのための一致する呼び出しがあることを前提としています。次のようなものがあります。

void canClose_driver(CAN_HANDLE handle) 
{ 
    int *fd = handle; 
    free(fd); 
} 
+0

ええ、それは私が今やっていることです。一方、私はまた、この非常に似たポストを見つけた:http://stackoverflow.com/questions/1327579/if-i-have-a-void-pointer-how-doput-an-int-int-it –

+0

...ファイル記述子以上のデータをプライベートデータとして保存する必要がある場合は、 'int'から' struct'に変更することができます。 – caf

2

アーキテクチャによっては、そのようになることがあります。私が正しく理解していれば、ドライバーは実際にあなたが提供するvoid *を決して使用しません。後でコードに戻すだけです。

sizeof(void *)> = sizeof(int)である限り、実際にはint型であると確信しているので、これらの型間でキャストすることは安全です。

サイズ条件を保証できない場合や、ハックに頼りたくない場合は、intにメモリを割り当ててそのメモリのアドレスを返す必要があります。たとえば、malloc()を使用したり、固定長配列にintを割り当てることができます。欠点は、もはや必要がなくなったらそのメモリを解放する必要があることです。私は、ドライバが、データ構造がもはや必要でなくなったときにあなたのコードにシグナルを送る何らかの通知を持っていると想像します。組み込みシステムで一般的に

0

、以下のCPUモデルが最も一般的です:

Data bus Address bus 

8 bit  16 bit 
8 bit  16+8 bit (banking) 
16 bit  16 bit 
16 bit  16+8 bit (banking) 
32 bit  32 bit 

一般的に、アドレスバスは常になります> =データバスより。私は、データバスがアドレスバスよりも大きいCPUを考えることはできません。

ここたりしないことがあり、問題を解決することがあり、やや汚いトリックです:

typedef union 
{ 
    CAN_HANDLE handle; 
    long  value; 

} CAN_HANDLE_t; 

は、これはおそらく、特定のシステム(遠いポインタなど)に、この組合を適応する必要がありますにもかかわらず、かなり移植する必要がありますが、 。

関連する問題