2010-12-02 3 views
2

私はこの種のものを多用し、いくつかのレガシーコードで働いている:あなたが見ることができるようにC - ポインタの配列、および使用状況を割り当てる - 型キャスト安全

// Allocate a look-up-table of pointers. 
long *pointerLUT = (long *) malloc(sizeof(long) * numPointers); 

... 


// Populate the array with pointers. 
for (int i=0; i<numPointers; i++) { 
    pointerLUT[i] = (long) NewFoo(); 
} 

... 


// Access the LUT. 
Foo *foo = (Foo *) pointerLUT[anIndex]; 

、これは配列を割り当て一般的なポインタ記憶域を使用するというアイデアを持っています。

Q1。このアプローチは安全ですか?

Q2。スタイル上、どのように改善することができますか?それは必要ですか? (型キャスティングは私の中に恐怖の猿をかきとります。)

ありがとう。

+0

'long'の代わりに' size_t'を使用してください... – smerlin

+1

@smerlin: 'uintptr_t'はより良いオプションです。Cの実装がポインタ型を整数に変換し、情報を失うことなく戻す機能をサポートしている場合は、おそらく 'uintptr_t'を提供します。 'uintptr_t'と' size_t'の違いは、 'uintptr_t'が提供されている場合、voidへの有効なポインタを保持することが保証され、voidへのポインタに変換されたときに元のものと等しくなることが保証されます。 – dreamlax

+0

@dreamlax:はい、それはすべてのコンパイラでは提供されていませんので、uintptr_tやintptr_tを使用する独自のtypedefを使用するとコンパイラでこれらの型が使用でき、他の型ではsize_tが最適な解決策になります...しかしほとんどの場合size_tとuintptr_tは同じ型を表します。 – smerlin

答えて

3

EDIT:私は彼が質問で "汎用ポインターストレージ"と言いました。この答えは、このケースでは正しくありません。

Fooへのポインタを使って作業している場合は、これがコードの意味です。

// Allocate a look-up-table of pointers. 
Foo **pointerLUT = (Foo **) malloc(sizeof(Foo *) * numPointers); 

// Populate the array with pointers. 
for (int i=0; i<numPointers; i++) { 
    pointerLUT[i] = NewFoo(); // NewFoo() should return (Foo *) 
} 

// Access the LUT. 
Foo *foo = pointerLUT[anIndex]; 
+0

テーブルは* generic *ポインタの格納に使用されているとの質問があります。ルックアップテーブルの各ポインタが 'Foo'を指しているかどうかは、おそらく分かっていないでしょう。 – dreamlax

+0

@dreamlax:あなたは正しいです、私はそれを見ませんでした。彼は 'void ** 'と付き合っているように見える – Blastfurnace

+0

あなたの助けに感謝します。 Blastfurnaceは、行うべき最良のことは、特定のタイプを使用することであると言って正しいです。私が「汎用」を意味するのは、プログラマーがポインタ配列のサイズに合わせた1つのソリューションとして、その用途に必要な型に型キャストするという、このアプローチをプロジェクト全体で使用したことです。しかし、個々の用途ごとに、1つのタイプのオブジェクトのみが参照されます。例えばFoo。私は弾丸を噛んで、Blastfurnaceのアプローチを使って書き直します。乾杯。 – SirRatty

5

A1:をvoid *に置き換える必要があります。sizeof(long)は必ずしもsizeof(void *)と同じではないためです。たとえばこれはlongが64

A2 32ビットおよびポインタですされ、64ビットのWindowsのセットアップ、上で動作しないでしょう。あなたがCを使用してvoid *場合は、からキャストしても大丈夫なので、あなたは、型キャストを使用する必要はありませんし、 〜void *

0

sizeof(long) == sizeof(void*)という保証はないので、コードは移植不可能です。少なくともvoid*の代わりにlongのコードを使用すると、コードのスタイルが改善されますが、それはどこからでも簡単に修正できるわけではありません。 Cにおいて

4

、タイプ(およびその逆)を整数へのポインタからの変換実装(これは実装は、これがサポートされているかどうか、および/またはそれがどのように行われるかを文書化しなければならないことを意味する)定義されます。また、voidへのポインタが同じサイズを持つことや、長い整数と同じ値を表すことができるという保証はありません。

例えば、タイプvoidへのポインタの配列を割り当てる方が良いだろう。

void **pointerLUT = malloc(sizeof (void *) * numPointers); 

// Populate the array with pointers. 
for (int i=0; i<numPointers; i++) { 
    pointerLUT[i] = NewFoo(); // implicit conversion to void * 
} 

// Access the LUT. 
Foo *foo = pointerLUT[anIndex]; // implicit conversion from void * 

(:5及び6部§6.3.2.3段落を参照5)整数は任意のポインタ型に変換できます。前述の場合を除き、 の結果は実装定義であり、正しく整列されず、参照される型の エンティティを指していない可能性があり、トラップ表現である可能性があります。

(6)ポインタ型は、整数型に変換することができます。前に指定した場合を除き、 の結果は実装定義です。結果が整数型で表現できない場合は、 の動作は未定義です。結果は任意の整数 タイプの値の範囲内にある必要はありません。

+0

'void * pointerLUT'ではなく' void ** pointerLUT'を使います。書かれているように、 'void *'を参照できないので、 'pointerLUT [anIndex]'はエラーです。 –

+0

'pointerLUT'がvoidポインターである場合、私はあなたがそうすることはできません。 – Blastfurnace

+0

@Adam Rosenfield:おっと!良いキャッチ。 – dreamlax

関連する問題