我想知道是否可以使用联合作为函数的参数:
假设我有两种结构:
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类型的指针(这是有意义的)......但是这样可以以这种方式使用联合吗?
答案 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参数。