16

プレーンCには優れた機能があります-void型ポインター。これは、任意のデータ型へのポインターとして使用できます。
ただし、次の構造体があると仮定します。


struct token {
    int type;
    void *value;
};

値フィールドは、char 配列、int、またはその他のものを指す場合があります。
したがって、この構造体の新しいインスタンスを割り当てるときは、次のものが必要です。

1) この構造体にメモリを割り当てます。
2) 値にメモリを割り当て、それを値フィールドに割り当てます。

私の質問は、void ポインターのような別の型にキャストできる「void 型の配列」を宣言する方法はありますか?

私が望むのは、任意の型にキャストできる「柔軟なメンバー配列」(C99 標準の 6.7.2.1 で説明) を使用することだけです。

このようなもの:


struct token {
    int type;
    void value[];
};

struct token *p = malloc(sizeof(struct token) + value_size);
memcpy(p->value, val, value_size);
...
char *ptr = token->value;

token->value を char または int 配列として宣言し、後で必要な型にキャストするとこの作業が行われると思いますが、後でこのコードを読む人にとっては非常に混乱する可能性があります。

4

6 に答える 6

5

まあ、まあ、それはおそらくあなたが望むものではないでしょう:

struct token {
  // your fields
  size_t item_size;
  size_t length
};

struct token *make_token(/* your arguments */, size_t item_size, size_t length)
{
    struct token *t = malloc(sizeof *t + item_size * length);
    if(t == NULL) return NULL;
    t->item_size = item_size;
    t->length    = length;
    // rest of initialization
}

x次のマクロを使用して、データのインデックスを作成できます (が であると仮定しますstruct token *)。

#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ?
                       (void *)(((char *)x[1]) + x->item_size * i)
                     : NULL : NULL)

そして、必要に応じて、次のマクロで関数をラップして、make_token関数をもう少し直感的にすることができます (または、そのように考えると、ハック風になります)。

#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)

使用法:

struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;
于 2011-04-25T22:20:14.150 に答える
1

私はおそらくこれを行うでしょう:

struct token {
    int type;
    void *value;
};

struct token p;

p.value = malloc(value_size);

p.value[0] = something;
p.value[1] = something;
...

編集、実際には、これらの p.value[index] = somethings を型キャストする必要があります。および/またはユニオンを使用して、型キャストする必要がないようにします。

于 2011-04-25T22:09:48.083 に答える
1

「void」アイテムの配列を持つことはできませんが、malloc を実行するときに value_size を知っている限り、必要なことができるはずです。しかし、それはきれいではありません。

struct token {
        int type;
        void *value;       
};    

value_size = sizeof(type)*item_count;
struct token *p = malloc(sizeof(struct token) + value_size);
//can't do memcpy:  memcpy(p->value, val, value_size);  
//do this instead
type* p = (type*)&(p->value);
type* end = p+item_count;
while (p<end) { *p++ = someItem; }

追加のストレージを取得する場合は、追加の address-of 演算子が必要になることに注意してください。

type *ptr = (type*)&(token->value); 

これは sizeof(void*) バイトを「浪費」し、元のタイプはあまり重要でvalueはないため、より小さな項目を使用することもできます。私はおそらくそのタイプtypedef char placeholder;を作るでしょう。value

于 2011-04-25T22:22:12.390 に答える
0

void 型の配列は、c/c++ ではサポートされていません。例:

int main() {

 void  alexa[]; // error: declaration of ‘alexa’ as array of void 

return 0;

}

void ポインターの配列は、c/c++ でサポートされています。以下の例:

int main(int argc, char argv*[]) 
{

void *alexa[100]; // Compiled successfully

return 0;

}
于 2021-03-12T17:40:47.953 に答える
0

次の構造が役立ちます。

struct clib_object_t {
void* raw_data;
size_t size;
};

struct clib_object_t*
new_clib_object(void *inObject, size_t obj_size) {
    struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t));   
    if ( ! tmp )
        return (struct clib_object_t*)0;
    tmp->size        = obj_size;
    tmp->raw_data    = (void*)malloc(obj_size);
    if ( !tmp->raw_data ) {
        free ( tmp );
        return (struct clib_object_t*)0;
    }
    memcpy ( tmp->raw_data, inObject, obj_size);
    return tmp;
}

clib_error
get_raw_clib_object ( struct clib_object_t *inObject, void**elem) {
    *elem = (void*)malloc(inObject->size);
    if ( ! *elem )
        return CLIB_ELEMENT_RETURN_ERROR;
    memcpy ( *elem, inObject->raw_data, inObject->size );

    return CLIB_ERROR_SUCCESS;
}

詳細: clibutils

于 2011-04-26T07:55:21.640 に答える