Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

355
Visualizações
void* as generic in C, is it safe?

get ready for a question a bit "twisted"...

I've implemented in the past a lot of data structure (tree, list, hash table, graph as well), using the macro i can implement some kind o generic. However i was wandering if it is possible to implement generic data structure using void pointer but somehow i would like to be able to use a typecheking...

I don't know if it is clear what i'm trying to say... but basically i don't think it is always safe to put "void*" as generic, at the same time i don't think is always a good idea to use the macro as way to make a generic data structure (since basically what a preprocessor does with the macro does is code substitution), because if you look around the web you can find such examples.

A good idea might be, in my opinion but probably i'm not right, is to use the macro for make a standard interface for the data stored in a data structure, among the interface functions i would put code for correct type checking, given a void*. Inspired by the software engineer techinique this could be a good way to proceed.

It is surely true that probably for too sofisticated stuff would be better to switch language (C++/Java) but it is even true that this is not always possible.

So in summary... how the problem of "generic" in C is usually handled? i rely on your experience for an answer!

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Briefly, there’s no convenient way to get type-safe generic data structures and functions in C.

Non-generic:

struct node {
  int value;
  struct node *next;
};

Generic, but unsafe—a void* has no type information:

struct node {
  void *value;
  struct node *next;
};

Safe, but ugly:

#define DECLARE_NODE_TYPE(type) \
  struct node_##type { \
    type value; \
    struct node_##type *next; \
  };

DECLARE_NODE_TYPE(int)
node_int *x = ...

Same idea, but slightly less ugly:

// declare_node_type.h

struct node_##NODE_TYPE {
  NODE_TYPE value;
  struct node_##NODE_TYPE *next;
};

#undef NODE_TYPE

// elsewhere

#define NODE_TYPE int
#include "declare_node_type.h"

node_int *x = ...

Generic and safe, but C++, not C:

template<typename T>
struct node {
  T value;
  node<T> *next;
};

node<int> *x = ...
over 4 years ago · Santiago Trujillo Relatório

0

You can do safer stuff with void*; getting back to the linked example of Jon Purdy:

typedef struct {
    union {
        void* data;  // generic data
        int idata;   // int is not stored dynamically
    };
    int type;    // additional type information
    Node* next;  // link
} Node;

#define NODE_TYPE_INT 0
Node* createNodeInt(Node* self, Node* next, int value) {
    self->idata = value;
    self->type = NODE_TYPE_INT;
    self->next = next;
    return self;
}

// in this case relying on user defined types...
Node* createNodeGeneric(Node* self, Node* next, void* data, int type) {
    assert(type != NODE_TYPE_INT && ..);
    self->data = data;
    self->type = type;
    self->next = next;
    return self;
}

Another approach is to use the common first member as the base type:

typedef struct {
    int type;
} Node;

#define TYPE_BINARY 0
typedef struct {
    Node base;
    Node* left;
    Node* right;
    int op;
} BinaryOp;

#define TYPE_LEAF_INT 1
typedef struct {
    Node base;
    int a;
} LeafInt;

#define TYPE_LEAF_FLOAT 2
typedef struct {
    Node base;
    float b;
} LeafFloat;

void op(BinaryOp* node) {
    switch(node->left.type) {
    case TYPE_BINARY:
        op((BinaryOp*)node->left);
        break;
    case TYPE_LEAF_INT:
        evalInt((LeafInt*)node->left);
        break;
    ...
    }
}

Node* foo() {
    LeafInt* left;
    LeafFloat* right;
    BinaryOp* op;
    // allocate
    ...
    // init
    createLeafInt(left, 42);
    createLeafFloat(right, 13.37);
    createBinaryOp(op, &left->base, &right->base);
    // and return
    return &op->base;
}
}
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda