2012-01-30 14 views
0

自分の学習効果のために、Cで共通のデータ構造を独自に実装しようとしています。私の現在の努力はベクトルであり、単一の任意の型(または少なくとも型のサイズを保持することができるようにしたいが、それはCの中で本当に重要なものすべてではない)。任意の型ポインタへのvoidポインタのキャスト

struct vector 
{ 
    void *item; 
    size_t element_size; 
    size_t num_elements; 
} 

は、しかし、私が理解していないことはタイプが任意であることになっている場合、私は*アイテムの配列内の特定の要素を参照することができる方法で次のように私の構造体があります。私はelement_sizeを知っていますが、voidは型ではないので、これはインデックスの参照に役立ちません(item [5]など)。私は、要素をバイトオフセットとして参照するのが最も簡単だと考えました。したがって、サイズ12の構造体のベクトルを保持していた場合、item [5]はitem *から12 * 5 = 60バイトになります。しかし、私はそのデータを取得する方法を理解していません。私はitem + 60から12バイトを欲しいと知っていますが、コンパイラはそれをどのように理解するのでしょうか?私はプリプロセッサ領域に入っていますか?

答えて

2

sizeofは文字で尺度であるので、あなたはこれを行うことができます:

void *start_of_sixth_element = ((char*)item) + (5 * element_size); 

各要素のタイプが何であるかを知っている人は、start_of_sixth_elementを正しいタイプにキャストして使用することができます。

void*あなたは、標準Cでvoid*ポインタとポインタ演算を行うことができないので、(そこにそれを可能にするためにGNUの拡張だが、移植可能なコードのためにあなたは、少なくとも演算にchar*unsigned char*を使用し、方法で、悪い選択であります)。オフセット5を適用する前に、正しい型を知っている

コードは、単にこれを行うことができます:

correct_type *sixth_element = ((correct_type *)item) + 5; 

ボイドタイプ

ではないことはそれだけではありません、タイプです"完全な型"。 「不完全な型」は、コンパイラがvoid*が実際に指しているものを知らないことを意味します。

+0

型を指定すると、 'element_size'の正しい値を簡単に見つけることができますか? (私は整列の必要条件を考えています) – NPE

+0

@aix:型が与えられた場合、 'element_size'は' sizeof(type) 'です:オブジェクトのサイズには、整列に必要なパディングが既に含まれています。アライメントは 'item'によって指されたメモリがどのように割り当てられたかによって決まります。 'malloc(element_size * num_elements) 'で割り振られていれば(乗算はオーバーフローしません)、' malloc'はすべてのオブジェクトに合わせてメモリを返すように保証されているので、整列の問題はありません。 SIMD命令のためのスーパーサイズの型は、実装によってはしばしば除外されるので、私はsnigger quotesを使用します。 –

+0

@aix、 'sizeof'演算子は、位置合わせを考慮に入れます。たとえば、 'long'が4バイトのアラインメントを持っている場合、' long'と 'char'を含む' struct'に 'sizeof'が適用されます。 – Lindydancer

0

void *は、任意のオブジェクトポインタ型の汎用ポインタ型です。 void *を正しくキャストしてポインタを間接参照するには、ポインタのタイプを知る必要があります。

ここには、異なるポインタタイプで使用されるvoid *オブジェクトの例があります。私はサイズ12と構造体のベクトルを保持していた場合

void *p; 
int a = 42, b; 
double f = 3.14159, g; 

p = &a; 
b = *(int *) a; 

p = &f; 
g = *(double *) f; 
0

だから、項目[5] *アイテムから12 * 5 = 60バイトであろう。しかし、私はそのデータを取得する方法を理解していません。私はitem + 60から12バイトを欲しいと知っていますが、コンパイラはそれをどのように理解するのでしょうか?

あなたの指定したタイプがfooであると言ってください。あなたがすでに理解しているように、アドレスitem + (5 * 12)に到達し、その後、それをキャストした後にfoo*に逆参照する必要があります。

foo my_stuff = *(foo *)(item + 5 * 12); 

あなたは、コンパイル時に、あなたのデータの種類を判別できる場合もsizeof()を使用することができます。

foo my_stuff = *(foo *)(item + 5 * sizeof(foo)); 
関連する問題