Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union as an argument to a function in C

I am wondering if it is possible to use unions as arguments to a function:

Let's say I have two structures:

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

struct generic_attribute{
    int current_value;
};

And a union of these two:

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

I want to create a function that takes in either a complex_attribute or a generic_attribute:

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

However, when I make a call to this function

prepare_tagged_attribute(2, pointer_to_complex_structure);

I get this error:

 passing argument 2 of ‘prepare_tagged_attribute’ from incompatible pointer type

So I take it that pointer to a a complex structure is not necessarily a pointer of type union (which makes sense)... but then is it possible to use unions in this way?

like image 330
RebeccaK375 Avatar asked Jun 26 '15 18:06

RebeccaK375


People also ask

How to pass the Union or the structure of a function?

The title is about passing the union, but the question asks about passing structure. You can do either, you simply declare the function argument accordingly and pass either the member or the whole union.

What is Union in C programming?

Last Updated : 08 Feb, 2019 Like Structures, union is a user defined data type. In union, all members share the same memory location. For example in the following C program, both x and y share the same location.

How do you pass a union as an argument in C89?

C89 has no real provision for initializing and passing unions as arguments directly. In C89 Unions can only be declared using variable or variable references and then must be initialized using the variable. However you then can pass and return these variables by value, so without using pointers.

How do I create a struct/union from an argument list?

With the utility functions create_GAIN_REG_st and GAIN_REG_st_to_G_u you can create the struct/union on the fly on the argument list to the call of your function, which is accepting these as parameter (s). Please note that this only works for non-pointer-types this way, as pointer must point somewhere.


1 Answers

If you're using GCC, and willing to use its language extensions, you can accomplish what you're trying to do with a transparent_union.

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

Transparent unions are designed for library functions that have multiple interfaces for compatibility reasons. For example, suppose the wait function must accept either a value of type int * to comply with Posix, or a value of type union wait * to comply with the 4.1BSD interface. If wait's parameter were void *, wait would accept both kinds of arguments, but it would also accept any other pointer type and this would make argument type checking less useful. Instead, might define the interface as follows:

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

      pid_t wait (wait_status_ptr_t);

In your example, you'd declare union_attribute like this:

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

And then you can call prepare_tagged_attribute exactly how you proposed.

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);
like image 156
Mike Andrews Avatar answered Oct 08 '22 02:10

Mike Andrews