如何将通用结构传递给C中的函数?

时间:2017-08-20 03:30:02

标签: c struct

我是C编程的初学者,我对将通用结构传递给C中的函数存在疑问。

这就是我所拥有的:

typedef struct {
    char name[20];
    float price;
} product;

typedef struct {
    char name[20];
    int type;
} category;

我想做这样的事情:

void changeName(struct *s, newName[20]) {
    strcpy(s->name, newName);
}

如果有人已经问过这个问题,请不要理会,并向我发送问题链接。

有人可以帮助我吗?

感谢。

3 个答案:

答案 0 :(得分:1)

使用union

一种方法是添加一个包含union的结构,其中包含指向productcategory结构的指针,以及enum以确定其类型struct中的数据。此union或指向它的指针可以传递给change_name()函数。

这是一个可以在C11中使用的示例。它使用未命名的union成员,因此这不是有效的C99代码:

#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");
    }
}

通过命名union

,可以在C99中使用它
typedef struct {
    enum { PRODUCT, CATEGORY } type;
    union {
        product *prod;
        category *cat;
    } data;                                  // named for 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");
    }
}

或者,一个struct类型可以包含enum标识符和包含产品和类别结构的union。这种方法似乎更精简:

#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");
    }
}

使用类型通用宏

上述两种方法都有点尴尬。另一种解决方案(仅适用于C11)是在类型通用宏中使用_Generic关键字。这里,为每个预期的数据类型编写函数,宏根据类型选择要使用的函数定义。这种方法的一个优点是,随着新类型的添加,只需要新的函数和类型通用宏的更新来处理它们。

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

以上所有程序都有相同的输出:

prod_a.name = widget
cat_a.name = general
prod_a.name = gadget
cat_a.name = specific

答案 1 :(得分:0)

您已经对结构进行了类型定义。您可以使用这些其他名称。

例如,如果名称为product,则首先创建一个变量并调用函数

product var={"name", 1.2};
changeName(&var, "AnotherName");

然后将此变量传递给函数

void changeName(product *s, char newName[])
{
    strcpy(s->name, newName);
}

答案 2 :(得分:-1)

通用编程,暗示类型安全只是在C中确实存在。但是有很多方法可以解决这个问题。

我从你的问题中理解的是,我能定义一个可以应用于不同结构的共同元素的函数吗?

让我们展开一些例子,让项目具有共同的特征。

struct info
{
    char name[20];
    int id;
};

struct product
{
   Info info;
   int price;
};

struct category
{
   Info info;
   int type;
};

您现在可以定义一个能够安全地处理产品和类别共享的特征的函数。

void changeName(info* p, const char* name)
{
    strcpy_s(info->name, sizeof(info->name), name);
}

int main()
{
    category cat;
    product prod;
    memset(&cat, 0, sizeof(cat));
    memset(&prod, 0, sizeof(prod));

    changeName(&cat.info, "Category 1");
    changeName(&prod.info, "blue product");

    return 0;
}