When Does an Incomplete Type Error Occur in C++

When does an Incomplete Type error occur in C++

This happens usually when the compiler has seen a forward declaration but no full definition of this type, while the type is being used somewhere. For example:

class A;

class B { A a; };

The second line will cause a compiler error and, depending on the compiler, will report an incomplete type (other compilers give you a different error, but the meaning is the same).

When you however just use a pointer to such a forward declaration no complain will come up, since the size of a pointer to a class is always known. Like this:

class A;
class B {
A *a;
std::shared_ptr<A> aPtr;
};

If you ask what could be wrong in a concrete application or library when this error comes up: that happens usually when a header is included which contains the forward declaration, but full definition hasn't been found yet. The solution is quite obvious: include also the header that gives you access to the full type. Sometimes you may also simply have no or the wrong namespace used for a type and need to correct that instead.

Why does my code say that it has an incomplete type even after I tried declaring it?

You have to define it first. You can also use this style.

struct student{
...
};

int main{
student* st[50];
for(int i=0; i<50;i++)
st[i]=new student;
return 0;
}

C++ How is this an Incomplete Type?

It's an incomplete type because you have not included the header for ClassA in the ClassB header but you're trying to use the ClassA instance. In other words, the compiler knows there is a ClassA thanks to the forward declaration, which is sufficient to declare a pointer, but the type is incomplete and cannot be used because the compiler hasn't seen the declaration of the type.

You need to make a source file (e.g., ClassB.cpp), include the ClassA header in the source file, and move the ClassB constructor's implementation to the source file.

If struct type is defined in another .c file, it becomes incomplete type?

A translation unit, i.e. one .c file and its #included .h files must be self-standing, containing in required order all the definitions and declarations needed to compile the translation unit. Even if you provide several .c files on a GCC command line, each of these files is considered a separate translation unit.

The in order means that the C source code of a translation unit can be compiled in single pass, meaning that the compiler could produce machine code at the same time as it parses the program, never having to keep in memory more than absolutely necessary, therefore all necessary declarations and definitions must appear in the source code before they are needed.

The C11/C18 standard says (6.5.3.4p1) that

The sizeof operator shall not be applied to an expression that has function type or an incomplete type [...]

And (6.7.2.3p4)


  1. All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type. Irrespective of whether there is a tag or what other declarations of the type are in the same translation unit, the type is incomplete*[129]* until immediately after the closing brace of the list defining the content, and complete thereafter.

With footnote 129 stating that

[129] An incomplete type may only by used when the size of an object of that type is not needed. It is not needed, for example, when a typedef name is declared to be a specifier for a structure or union, or when a pointer to or a function returning a structure or union is being declared. (See incomplete types in 6.2.5.) The specification has to be complete before such a function is called or defined.

i.e. you translation unit a.c consists of the following code:

// code included from <stdio.h>
...
// code included from "b.h"
struct foo;

// rest of code in a.c
int main()
{
printf("%lu\n",sizeof(struct foo));
}

This is all knowledge that the C compiler has of struct foo, and by the time it hits the sizeof(struct foo), by 6.7.2.3p4 the type struct foo is still incomplete and an error is produced.

As a fix, the b.h should, instead of the completely useless and no-op struct foo; have the actual structure definition:

b.h:

struct foo
{
void * data;
};

Incomplete type error when compiled with g++

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

typedef struct leads to pointer to incomplete type not allowed error

In the translation unit where the function rec_fn is defined the compiler sees only the following declaration

typedef struct _httpc_state httpc_state_t;

It knows nothing about whether the data member timeout_ticks used in this statement

req->timeout_ticks = 30;

is indeed declared within the structure struct _httpc_state and what is its type. That is the name timeout_ticks is undeclared in this translation unit. So the compiler issues an error.

If you are going to use data members of the structure in a translation unit then the compiler needs to know their declarations. That is you need also to include the structure definition.

Either move the structure definition in the header if you are allowed to do that or duplicate its definition in the module where your function is defined.

Pay attention to that if the structure definition was not placed in the header then the reason of that can be that the author of the code does not want to make it available outside his module or library.

A class has incomplete type

The problem is that when you wrote:

void A_lookup(B b){ //this statement needs B to be a complete type
cout << b.b_i <<endl; //this also needs B to be a complete type
}

In the above member function definition, the parameter b is of type B. And for B b to work, B must be a complete type. Since you have only declared class B and not defined it, you get the mentioned error. Moreover, the expression b.b_i needs B to be a complete type as well.

Solution

You can solve this by declaring the member function A_lookup inside the class A and then defining it later when B is a complete type as shown below:

#include <iostream>
class B;
class A{
public:
int a_i=10;

//only a declaration here
void A_lookup(B b);
};
class B{
public:
int b_i=20;
void B_lookup(A a){
std::cout << a.a_i <<std::endl;
}
};
//this is a definition. At this point B is a complete type
void A::A_lookup(B b)
{
std::cout << b.b_i <<std::endl;
}
int main(void){
A a;
B b;
a.A_lookup(b);
}

Demo

Solution 2

Note that you can also make the parameters a and b to be a reference to const A or reference to const B respectively as shown below. Doing so has some advantages like now the parameter a and b need not be complete type. But still expression a.a_i and b.b_i will need A and B respectively to be complete type. Also, now the argument will not be copied since now they will be passed by reference instead of by value.

#include <iostream>
class B;
class A{
public:
int a_i=10;
void A_lookup(const B& b); //HERE ALSO void A_lookup(const B& b){ std::cout << b.b_i <<std::endl;} WILL NOT WORK

};
class B{
public:
int b_i=20;
void B_lookup(const A& a){
std::cout << a.a_i <<std::endl;
}
};

void A::A_lookup(const B& b)
{
std::cout << b.b_i <<std::endl;
}
int main(void){
A a;
B b;
a.A_lookup(b);
}

Demo


Also refer to Why should I not #include <bits/stdc++.h>?.

C Programming: parameter has incomplete type error

typedef struct ClientInfo ClientInfo;

This is a forward declaration - a declaration of an incomplete type that will later on get completed in your client.c file. However, this design with a forward declaration in a header file makes the contents of the struct private.

No other file in your program will know what the struct contains, nor will they be able to access members. For them, the struct will still be incomplete and therefore they can't declare variables of this struct type. They can however declare pointers to the struct.

This is actually how you do private encapsulation of objects in C. The concept is called "opaque type" and is considered good OO design practice.

What you can do to fix the problems, is to change all functions in "client.h" and "client.c" so that they work with ClientInfo* pointers instead. Then every other file using ClientInfo will have to use pointers. Since they won't be able to declare any object of that type, you'll have to provide a constructor (and destructor). For example:

ClientInfo* client_create (void)
{
return malloc(sizeof(ClientInfo));
}


Related Topics



Leave a reply



Submit