1

I am trying to execute following code using g++ and getting incomplete type error

#include <stdio.h>
struct try_main{
  union{
    struct try_inner_one{
      int fl;
      float g;
    }one;
    struct try_inner_two{
      char a;
    }two;
  }un;
  int chk;
};

void func(struct try_inner_one o){
  printf("%d\n",o.fl);
}
int main(){
  struct try_main z = {{1,2},3};
  func(z.un.one);
return 0; 
}

Error:

union.c: In function ‘void func(try_inner_one)’:
union.c:15:6: error: ‘o’ has incomplete type
 void func(struct try_inner_one o){
      ^
union.c:15:18: error: forward declaration of ‘struct try_inner_one’
 void func(struct try_inner_one o){
                  ^
union.c: In function ‘int main()’:
union.c:20:16: error: parameter 1 of ‘void func(try_inner_one)’ has incomplete type ‘try_inner_one’
   func(z.un.one);

Above code is successfully getting compiled with gcc

What is the reason for this error and how to fix this

Thanks

timrau
  • 22,578
  • 4
  • 51
  • 64
Karthik K M
  • 619
  • 2
  • 9
  • 24

3 Answers3

4

C and C++ have different scoping rules. The full name of the type in C++ isn’t struct try_inner_one, since the type definition is nested inside the unnamed union inside try_main.1

If you want to write code that works equally in both C and C++, pull the type definition to the top level:

struct try_inner_one {
  int fl;
  float g;
};

struct try_inner_two {
  char a;
};

struct try_main {
  union {
    struct try_inner_one one;
    struct try_inner_two two;
  } un;
  int chk;
};

1 The fully qualified name of this type can’t be spelled in C++ since the type it’s nested inside is unnamed. You could give a name to the union type, that would allow you to spell the fully qualified name of try_inner_one in C++. However, that name wouldn’t be legal C code, since C doesn’t have a scope resolution operator.

If you want to keep the nested type definition you could give the union a name (in the following, union_name) and do the following to keep the code compiling for both C and C++:

// (Type definition omitted.)

#ifdef __cplusplus
using try_inner_one = try_main::union_name::try_inner_one;
#else
typedef struct try_inner_one try_inner_one;
#endif

void func(try_inner_one o){
  printf("%d\n", o.fl);
}
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
2

What is the reason for this error

The reason is that try_inner_one nested within the union nested within try_main cannot be found by unqualified name lookup in the context outside of that union in C++ (unlike in C).

how to fix this

You can use a qualified name in C++:

void func(decltype(try_main::un)::try_inner_one o){

You can simplify if you give a name for the union:

union u { // note the name
    struct try_inner_one{

void func(try_main::u::try_inner_one o){

A cross-language compatible solution is to define the struct outside of each other as described in Kondrad Rudolph's answer.


A word of warning: C++ is more restrictive than C on how inactive members of union can be accessed.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

It seems you are compiling your program as a C++ program. In this case each declaration within the structure try_main has the scope of this structure.

So you need to declare the function like

void func( decltype( try_main::un )::try_inner_one o );

or

void func( const decltype( try_main::un )::try_inner_one &o );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335