How can I pass a generic struct to a function in C? -
i'm beginner in c programming , have doubt pass generic struct function in c.
here have:
typedef struct { char name[20]; float price; } product; typedef struct { char name[20]; int type; } category;
and want this:
void changename(struct *s, newname[20]) { strcpy(s->name, newname); }
if has asked that, please disconsider , sends me issue link.
someone can me?
thanks.
using union
one approach add structure containing union
, containing pointers product
, category
structures, enum
identify type of data in struct
. union
, or pointer it, passed change_name()
function.
here example work in c11. uses unnamed union
member, not valid c99 code:
#include <stdio.h> #include <string.h> typedef struct { char name[20]; float price; } product; typedef struct { char name[20]; int type; } category; typedef struct { enum { product, category } type; union { product *prod; category *cat; }; } generic; void change_name(generic *gen, const char *new_name); int main(void) { product prod_a = { .name = "widget", .price = 1.99 }; category cat_a = { .name = "general", .type = 1 }; generic gen_prod_a = { .type = product, .prod = &prod_a }; generic gen_cat_a = { .type = category, .cat = &cat_a }; printf("prod_a.name = %s\n", prod_a.name); printf("cat_a.name = %s\n", cat_a.name); change_name(&gen_prod_a, "gadget"); change_name(&gen_cat_a, "specific"); printf("prod_a.name = %s\n", prod_a.name); printf("cat_a.name = %s\n", cat_a.name); return 0; } void change_name(generic *gen, const char *new_name) { switch (gen->type) { case product: strcpy(gen->prod->name, new_name); break; case category: strcpy(gen->cat->name, new_name); break; default: fprintf(stderr, "unknown type in change_name()\n"); } }
this made work in c99 naming union
:
typedef struct { enum { product, category } type; union { product *prod; category *cat; } data; // named c99 } generic; /* ... */ generic gen_prod_a = { .type = product, .data.prod = &prod_a }; generic gen_cat_a = { .type = category, .data.cat = &cat_a }; /* ... */ void change_name(generic *gen, const char *new_name) { switch (gen->type) { case product: strcpy(gen->data.prod->name, new_name); break; case category: strcpy(gen->data.cat->name, new_name); break; default: fprintf(stderr, "unknown type in change_name()\n"); } }
alternatively, 1 struct
type hold enum
identifier , union
containing product , category structures. approach may seem bit more streamlined:
#include <stdio.h> #include <string.h> typedef struct { enum { product, category } type; union { struct { char name[20]; float price; } prod; struct { char name[20]; int type; } cat; } data; } record; void change_name(record *rec, const char *new_name); int main(void) { record prod_a = { .type = product }; change_name(&prod_a, "widget"); prod_a.data.prod.price = 1.99; record cat_a = { .type = category }; change_name(&cat_a, "general"); cat_a.data.cat.type = 1; printf("prod_a.name = %s\n", prod_a.data.prod.name); printf("cat_a.name = %s\n", cat_a.data.cat.name); change_name(&prod_a, "gadget"); change_name(&cat_a, "specific"); printf("prod_a.name = %s\n", prod_a.data.prod.name); printf("cat_a.name = %s\n", cat_a.data.cat.name); return 0; } void change_name(record *rec, const char *new_name) { switch (rec->type) { case product: strcpy(rec->data.prod.name, new_name); break; case category: strcpy(rec->data.cat.name, new_name); break; default: fprintf(stderr, "unknown type in change_name()\n"); } }
using type-generic macro
both of above approaches little bit awkward. solution, available c11 only, use _generic
keyword in type-generic macro. here, functions written each expected data type, , macro selects function definition used based on type. virtue of approach new types added, new functions , updates type-generic macro needed handle them.
#include <stdio.h> #include <string.h> #define change_name(s, n) _generic ((s), \ prod_ptr: change_name_prod, \ cat_ptr: change_name_cat \ )((s), (n)) typedef struct { char name[20]; float price; } product; typedef struct { char name[20]; int type; } category; typedef product *prod_ptr; typedef category *cat_ptr; void change_name_prod(product *prod, const char *new_name); void change_name_cat(category *cat, const char *new_name); int main(void) { product prod_a = { .name = "widget", .price = 1.99 }; category cat_a = { .name = "general", .type = 1 }; printf("prod_a.name = %s\n", prod_a.name); printf("cat_a.name = %s\n", cat_a.name); change_name(&prod_a, "gadget"); change_name(&cat_a, "specific"); printf("prod_a.name = %s\n", prod_a.name); printf("cat_a.name = %s\n", cat_a.name); return 0; } void change_name_prod(product *prod, const char *new_name) { strcpy(prod->name, new_name); } void change_name_cat(category *cat, const char *new_name) { strcpy(cat->name, new_name); }
all of above programs have same output:
prod_a.name = widget cat_a.name = general prod_a.name = gadget cat_a.name = specific
Comments
Post a Comment