Array vom Typ void

Lesezeit: 5 Minuten

Benutzer-Avatar
SJ

Plain C hat ein nettes Feature – Zeiger vom Typ void, die als Zeiger auf jeden Datentyp verwendet werden können.
Aber nehmen wir an, ich habe folgende Struktur:


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

Dabei kann das Wertfeld auf ein char-Array oder auf int oder etwas anderes zeigen.
Wenn ich also eine neue Instanz dieser Struktur zuweise, brauche ich:

1) Speicher für diese Struktur zuweisen;
2) Weisen Sie Speicher für den Wert zu und weisen Sie ihn dem Wertfeld zu.

Meine Frage ist – gibt es Möglichkeiten zu deklarieren “Reihe vom Typ void”, der in einen anderen Typ wie void pointer gecastet werden kann?

Alles, was ich möchte, ist die Verwendung von “Flexible Member Array” (beschrieben in 6.7.2.1 des C99-Standards) mit der Fähigkeit, in jeden Typ umzuwandeln.

Etwas wie das:


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;

Ich nehme an, dass das Deklarieren von token-> value als char- oder int-Array und das spätere Casting in den erforderlichen Typ diese Arbeit erledigt, aber für jemanden, der diesen Code später lesen wird, sehr verwirrend sein kann.

  • verwenden char[] ist imho in Ordnung, da sizeof(char) == 1 und Sie werden nie überrascht sein. Möglicherweise möchten Sie Makros für den Zugriff in Betracht ziehen p->value mit dem richtigen Typ.

    – Alexander C.

    25. April 2011 um 22:20 Uhr

Nun, irgendwie, aber es ist wahrscheinlich nicht etwas, was Sie wollen:

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
}

Das folgende Makro kann verwendet werden, um Ihre Daten zu indizieren (vorausgesetzt x ist ein struct token *):

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

Und wenn Sie möchten, kann das folgende Makro Ihre umschließen make_token Funktion, um es etwas intuitiver zu machen (oder hackisher, wenn Sie so darüber nachdenken):

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

Verwendungszweck:

struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;

Wenn Sie die Antwort von AShelly erweitern, können Sie dies tun.

/** A buffer structure containing count entries of the given size. */
typedef struct {
    size_t size;
    int count;
    void *buf;
} buffer_t;

/** Allocate a new buffer_t with "count" entries of "size" size. */
buffer_t *buffer_new(size_t size, int count)
{
    buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size);
    if (p) {
        p->size = size;
        p->count = count;
    }
    return p;
}

Beachten Sie die Verwendung von „offsetof()“ anstelle von „sizeof()“, wenn Sie den Speicher zuweisen, um zu vermeiden, dass „void *buf;“ verschwendet wird. Feldgröße. Die Art von „buf“ spielt keine große Rolle, aber die Verwendung von „void *“ bedeutet, dass das „buf“-Feld in der Struktur optimal für einen Zeiger ausgerichtet wird, wobei bei Bedarf eine Auffüllung davor hinzugefügt wird. Dies führt normalerweise zu einer besseren Speicherausrichtung für die Einträge, insbesondere wenn sie mindestens so groß wie ein Zeiger sind.

Der Zugriff auf die Einträge im Puffer sieht so aus;

/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
    return &t->buf + i * t->size;
}

Beachten Sie den zusätzlichen address-of-Operator, um die Adresse des “buf”-Felds als Ausgangspunkt für den zugewiesenen Eintragsspeicher zu erhalten.

  • Eine kleine Anfängerfrage in diesem Statement: buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size); müssen Sie keine zusätzliche hinzufügen count * sizeof(int) zur Rechenschaft ziehen count Feld in der Struktur? Oder gehst du davon aus size Feld enthält bereits die Größe der int?

    – Abhiroop Sarkar

    11. Mai 2019 um 1:16 Uhr

  • In meinem Beispiel ist das Feld „Größe“ die Größe jedes Eintrags in Byte, und Anzahl ist die Anzahl der zugewiesenen Einträge, sodass es nur eine Anzahl pro Array von Einträgen gibt.

    – Donovan Baarda

    12. Mai 2019 um 4:06 Uhr

Ich würde wahrscheinlich so vorgehen:

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

struct token p;

p.value = malloc(value_size);

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

bearbeiten, eigentlich müssen Sie diese p.value typisieren[index] = etwas. Und/oder verwenden Sie eine Union, um keine Typumwandlung durchführen zu müssen.

  • Du müsstest werfen p.value bevor Sie es verwenden.

    – Chris Lutz

    25. April 2011 um 22:11 Uhr

  • p.value[0] = something wird sicherlich einen Kompilierzeitfehler ergeben? Man kann a nicht dereferenzieren void*.

    – Robᵩ

    25. April 2011 um 22:12 Uhr

  • Dies wird nicht einmal kompiliert. Einige Compiler erlauben Pointer-Arithmetik on void * -Zeiger (als Erweiterung), aber alle verbieten die Dereferenzierung von void-Zeigern.

    – AnT steht zu Russland

    25. April 2011 um 22:13 Uhr


Folgende Struktur kann Ihnen dabei helfen.

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;
}

Mehr Details : clibutils

Benutzer-Avatar
Mukesh Kumar

Anordnung von Typ leer ist nicht Unterstützung in c/c++. Beispiel wie:

int main() {

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

return 0;

}

Anordnung von ungültiger Zeiger wird in c/c++ unterstützt. Beispiel unten:

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

void *alexa[100]; // Compiled successfully

return 0;

}

1037890cookie-checkArray vom Typ void

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy