联盟作为C中函数的参数

时间:2015-06-26 18:27:53

标签: c function structure unions

我想知道是否可以使用联合作为函数的参数:

假设我有两种结构:

struct complex_attribute{
    struct generic_attribute *sub_attributes[20];
};

struct generic_attribute{
    int current_value;
};

这两者的结合:

union union_attribute{
    struct complex_attribute *complex;
    struct generic_attribute *generic;
};

我想创建一个接受complex_attribute或generic_attribute:

的函数
struct tagged_attribute* prepare_tagged_attribute(int code, union union_attribute *attribute)

但是,当我调用此函数时

prepare_tagged_attribute(2, pointer_to_complex_structure);

我收到此错误:

 passing argument 2 of ‘prepare_tagged_attribute’ from incompatible pointer type

所以我认为指向一个复杂结构的指针不一定是union类型的指针(这是有意义的)......但是这样可以以这种方式使用联合吗?

6 个答案:

答案 0 :(得分:3)

由于C中没有多态或过载,我不确定是否有完美的解决方案。

只要您将指针包裹在union_attribute

中,您的解决方案就可以正常运行
union union_attribute argument;
argument.complex = pointer_to_complex_structure;
prepare_tagged_attribute(2, &argument);

你必须做这个包装有点烦人,所以一个选择就是引入一个新功能为你做这个:

union union_attribute wrap_complex(struct complex_attribute* attr) {
    union union_attribute result;
    result.complex = attr;
    return result;
}

然后,重写您的prepare_tagged_attribute函数以按值union而不是指针:

struct tagged_attribute* prepare_tagged_attribute(int code, union union_attribute attribute)

然后,你可以说像

prepare_tagged_attribute(2, wrap_complex(pointer_to_complex_structure));

当然,它并不完美,但它的工作和类型检查。

希望这有帮助!

答案 1 :(得分:3)

如果您正在使用GCC,并且愿意使用其语言扩展程序,则可以使用transparent_union完成您要执行的操作。

来自https://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Type-Attributes.html

  

透明联合是为具有的库函数而设计的   出于兼容性原因的多个接口例如,假设   wait函数必须接受int *类型的值才能遵守   使用Posix,或者类型为union wait *的值,以符合4.1BSD   接口。如果wait的参数为void *,则wait将同时接受这两个参数   各种参数,但它也会接受任何其他指针类型   这会使参数类型检查变得不那么有用。代替,    可以按如下方式定义接口:

      typedef union
        {
          int *__ip;
          union wait *__up;
        } wait_status_ptr_t __attribute__ ((__transparent_union__));

      pid_t wait (wait_status_ptr_t);

在您的示例中,您将声明union_attribute,如下所示:

typedef union {
    struct complex_attribute *complex;
    struct generic_attribute *generic;
} union_attribute __attribute__ ((__transparent_union__));

然后你可以准确地致电prepare_tagged_attribute

struct tagged_attribute* prepare_tagged_attribute(int code, union_attribute attribute)
{
   attribute.generic_attribute->current_value = 1; // e.g.
   return NULL; // e.g.
}

prepare_tagged_attribute(code, pointer_to_complex_structure);

答案 2 :(得分:1)

当您声明函数采用union参数时,您必须实际传递 union参数,而不是指针。

旁注:如果使用gcc,请查看transparent_union属性。这对你来说可能很有趣,因为它实际上允许上面的用法。请注意,但是,您仍然需要发出通过哪种类型的参数的信号(与标准方式一样多。

一种可能更好的方法是将类型和值信息捆绑在单个结构中,如:

struct variable_argument {
    enum {
        COMPLEX_ARG, GENERIC_ARG
    } type;
    union union_attribute{
        struct complex_attribute *complex;
        struct generic_attribute *generic;
    };
};

并将指向此类结构的指针传递给该函数。注意我使用匿名结构字段  为工会(自C99)。这样您可以参考以下字段:

struct variable_argument s;

... s.complex = ...

但是,如果更改了联合的类型,永远不要忘记设置s.type

这个结构实际上将指针与其他结构之一相关联。但是,您可以直接在联合中使用它们而不是使用指针。这简化了内存分配/释放。

答案 3 :(得分:1)

您无法(便携)将union_attribute*投射到#include <stdio.h> struct generic_attribute{ int current_value; }; struct complex_attribute{ struct generic_attribute *sub_attributes[20]; }; union union_attribute{ struct complex_attribute *complex; struct generic_attribute *generic; }; struct tagged_attribute* prepare_tagged_attribute(int code, union union_attribute *attribute) { if (code == 1) { printf("in func, generic_attribute is %p\n", attribute->generic); } else { printf("in func, complex_attribute is %p\n", attribute->complex); } return NULL; } int main() { struct generic_attribute g; printf("in main, generic_attribute is %p\n", &g); prepare_tagged_attribute(1, &(union union_attribute){.generic=&g}); struct complex_attribute c; printf("in main, complex_attribute is %p\n", &c); prepare_tagged_attribute(2, &(union union_attribute){.complex=&c}); return 0; } 。但是,如果你正在使用C99,你可以使用所谓的&#34;复合文字&#34;有效地创建一个未命名的联合,初始化其中的成员,获取其地址,并将其传递给您的函数,所有这一切。其他答案似乎都没有提到这一点 - 这是一个展示这种方法的工作计划:

emit

有关此技术的详细信息,请参阅the section on Compound Literals in the standard。自C99以来它已经可用,但它在C ++中不可用,许多C程序员似乎都不知道它。

答案 4 :(得分:0)

根本不要使用工会。由于您还传递了指示正在使用何种指针的代码,因此请使用指向void的指针并仅传递结构指针:

prepare_tagged_attribute(2, pointer_to_complex_structure);

然后根据代码动态转换指针:

if( code == 2 ){
    struct complex_attribute* p = attribute ;
}

答案 5 :(得分:0)

我只是声明函数采用两种参数类型

prepare_tagged_attribute(struct complex_attribute *complex,struct generic_attribute *generic)

处理第一个非NULL参数。