dereferencing pointer to incomplete type - c

I've seen a lot of questions on this but I'm going to ask the question differently without specific code. Is there a way of EASILY determining what is causing the type to be incomplete? In my case I'm using someone elses code and I'm completely sure I don't have the headers right, but (since computers do this stuff much faster and better than human eyeballs) is there a way to get the compiler to say, "hey you think you have type X at line 34 but that's actually missing." The error itself only shows up when you assign, which isn't very helpful.

I saw a question the other day where someone inadvertently used an incomplete type by specifying something like
struct a {
int q;
};
struct A *x;
x->q = 3;
The compiler knew that struct A was a struct, despite A being totally undefined, by virtue of the struct keyword.
That was in C++, where such usage of struct is atypical (and, it turns out, can lead to foot-shooting). In C if you do
typedef struct a {
...
} a;
then you can use a as the typename and omit the struct later. This will lead the compiler to give you an undefined identifier error later, rather than incomplete type, if you mistype the name or forget a header.

Another possible reason is indirect reference. If a code references to a struct that not included in current c file, the compiler will complain.
a->b->c //error if b not included in current c file

What do you mean, the error only shows up when you assign? For example on GCC, with no assignment in sight:
int main() {
struct blah *b = 0;
*b; // this is line 6
}
incompletetype.c:6: error: dereferencing pointer to incomplete type.
The error is at line 6, that's where I used an incomplete type as if it were a complete type. I was fine up until then.
The mistake is that you should have included whatever header defines the type. But the compiler can't possibly guess what line that should have been included at: any line outside of a function would be fine, pretty much. Neither is it going to go trawling through every text file on your system, looking for a header that defines it, and suggest you should include that.
Alternatively (good point, potatoswatter), the error is at the line where b was defined, when you meant to specify some type which actually exists, but actually specified blah. Finding the definition of the variable b shouldn't be too difficult in most cases. IDEs can usually do it for you, compiler warnings maybe can't be bothered. It's some pretty heinous code, though, if you can't find the definitions of the things you're using.

I don't exactly understand what's the problem. Incomplete type is not the type that's "missing". Incompete type is a type that is declared but not defined (in case of struct types). To find the non-defining declaration is easy. As for the finding the missing definition... the compiler won't help you here, since that is what caused the error in the first place.
A major reason for incomplete type errors in C are typos in type names, which prevent the compiler from matching one name to the other (like in matching the declaration to the definition). But again, the compiler cannot help you here. Compiler don't make guesses about typos.

this error usually shows if the name of your struct is different from the initialization of your struct in the code, so normally, c will find the name of the struct you put and if the original struct is not found, this would usually appear, or if you point a pointer pointed into that pointer, the error will show up.

A - Solution
Speaking for C language, I've just found ampirically that following declaration code will be the solution;
typedef struct ListNode
{
int data;
ListNode * prev;
ListNode * next;
} ListNode;
So as a general rule, I give the same name both for both type definition and name of the struct;
typedef struct X
{
// code for additional types here
X* prev; // reference to pointer
X* next; // reference to pointer
} X;
B - Problemetic Samples
Where following declarations are considered both incomplete by the gcc compiler when executing following statement. ;
removed->next->prev = removed->prev;
And I get same error for the dereferencing code reported in the error output;
>gcc Main.c LinkedList.c -o Main.exe -w
LinkedList.c: In function 'removeFromList':
LinkedList.c:166:18: error: dereferencing pointer to incomplete type 'struct ListNode'
removed->next->prev = removed->prev;
For both of the header file declarations listed below;
typedef struct
{
int data;
ListNode * prev;
ListNode * next;
} ListNode;
Plus this one;
typedef struct ListNodeType
{
int data;
ListNode * prev;
ListNode * next;
} ListNode;

Outside of possible scenarios involving whole-program optimization, the code code generated for something like:
struct foo *bar;
struct foo *test(struct foo *whatever, int blah)
{
return blah ? whatever: bar;
}
will be totally unaffected by what members struct foo might contain. Because make utilities will generally recompile any compilation unit in which the complete definition of a structure appears, even when such changes couldn't actually affect the code generated for them, it's common to omit complete structure definitions from compilation units that don't actually need them, and such omission is generally not worthy of a warning.
A compiler needs to have a complete structure or union definition to know how to handle declarations objects of the type with automatic or static duration, declarations of aggregates containing members of the type, or code which accesses members of the structure or union. If the compiler doesn't have the information needed to perform one of the above operations, it will have no choice but to squawk about it.
Incidentally, there's one more situation where the Standard would allow a compiler to require a complete union definition to be visible but would not require a diagnostic: if two structures start with a Common Initial Sequence, and a union type containing both is visible when the compiler is processing code that uses a pointer of one of the structure types to inspects a member of that Common Initial Sequence, the compiler is required to recognize that such code might be accessing the corresponding member of a structure of the other type. I don't know what compilers if any comply with the Standard when the complete union type is visible but not when it isn't [gcc is prone to generate non-conforming code in either case unless the -fno-strict-aliasing flag is used, in which case it will generate conforming code in both cases] but if one wants to write code that uses the CIS rule in such a fashion as to guarantee correct behavior on conforming compilers, one may need to ensure that complete union type definition is visible; failure to do so may result in a compiler silently generating bogus code.

Related

Prevent incomplete type declaration when defining opaque pointer?

There's a feature in the C standard that was hiding a bug in my code, and I'd like to know if there's some way of preventing it, or at least issuing a warning.
In C, this code implicitly declares struct foo as an incomplete type:
struct foo *ptr; /* I didn't even tell the compiler I wish to use struct foo */
However, I'd prefer to be required to declare the incomplete type instead, like this:
struct foo; /* foo is incomplete, but I'm telling the compiler to allow references to foo */
struct foo *ptr; /* that's fine, pointer to an incomplete type which I said I wish to use */
The bug I was talking about is that I made a typo in a pointer definition, and so it was pointing to an incomplete type that was created "on the fly" by the compiler with no warning. Had the compiler warned me with something like "pointer to undeclared struct", I would have corrected the typo. Can I enable such a warning in some way?
The pointer itself is OK provided you do not dereference it or use it in a way which requires the complete type.
If you try you will get an error.
Examples:
struct foo; /* foo is incomplete, but I'm telling the compiler to allow references to foo */
void foo(void *vptr)
{
struct foo *ptr = ptr;
ptr -> x = 0; //error
}
#include <stdlib.h>
struct foo; /* foo is incomplete, but I'm telling the compiler to allow references to foo */
void foo(void)
{
struct foo *ptr = malloc(sizeof(*ptr)); // error - incomplete type
}
https://godbolt.org/z/bnKEGr
There is no need for additional warning messages as the pointer to incomplete type is valid.
You cannot allocate an object of incomplete type unless the definition is present in the same translation unit as the variable. That's the whole point of using opaque pointers - the type is completed by the struct definition in the corresponding .c file which will not be visible to the caller.
There's two ways to implement them, either as a typedef in a header without pointers:
typedef struct foo foo;
or as a pointer:
typedef struct foo* foo;
The former style has the advantage that you don't hide pointers behind typedef, which is often confusing. Your API would then be for example void foo_init (foo* f); and the caller must declare all instances as pointers.
The latter style has the advantage that you can pretend that the opaque type is a common variable. This allows the caller to seemingly declare objects, while they are actually declaring pointers without realizing. The API then becomes void foo_init (foo f); where everything appears to be passed by value.
The problem with your error is that you can make the typo anywhere in the code, and the compiler cannot know if you will finally complete the type or not (it is valid not to complete the type and there are some uses of that ---e.g. opaque types)
Opaque types are normally managed by reference, you define an incomplete structure that you export in a public header file, and you complete in a private header file. The implementation module includes both files (includes the private only, but as the private will include the public, you have both) and the library user includes only the public, wich has the incomplete. This way you can manage a library of objects for which you don't know the internal structure, but the implementation has full access to them. And as pointer to different structures are different types of pointers you have a weak type checking.
But all of this requires that the compiler shuts up when it reaches the end of a compilation unit and some of the types have not been completed.

Problem with C nested structure. error: invalid use of incomplete typedef

For the sake of simplicity I'm going to recreate the actual situation with dummy structures. I have this structure (not my code, I can't edit it):
// private_header_a.h
struct A_s{
int a1;
};
// header_a.h
typedef struct A_s A_t;
Then in one of my headers I extended it this way:
// my_header.h
typedef struct B_s{
A_t* a_f;
int b1;
} B_t;
Now, in my function, I have:
B_t* b;
// Initialization and some other code
b->b1 = 4; // Just an example and compiler does not give any error
// Some other code
b->a_f->a1;
This last line of code makes the compiler throw this error:
error: invalid use of incomplete typedef ‘A_t’ {aka ‘struct A_s’}
Where is the error?
EDIT: the piece of code that triggers the compiler has header_a.h and my_header.h included. private_header_a.h cannot be included directly as not installed (I should copy-paste it, but frankly I would like to avoid to do that)
The compiler error is probably intentional - the library's designers don't want you using A_t directly in that sort of way.
When a struct is only declared in a library's public header file, and only defined in the library's private implementation files, that means you're not supposed to know or care about its members or even size. So looking up that the struct has a member named a1 and writing b->af->a1 is not the intended use. This arrangement is called an "opaque handle". A few of its benefits are that the library keeps your application code from initializing or changing members in ways that don't make sense, and a future version of the library can change the names, numbers, and meanings of the members without breaking your application code.
(Also, how did you get a valid pointer for b->af without doing malloc(sizeof(A_t)) or similar? That sizeof would also cause a compiler error about the incomplete struct type.)
When a library uses an opaque handle, since you can't create any such objects yourself, it will typically provide functions that create the objects for you. Look for public functions in the library with names including init, create, open, etc. which return an A_t* pointer, and read their documentation. Usually there will also be a corresponding destroy, cleanup, close, etc. function which the program should call later when the library object is no longer needed. (In the case of some very simple handles, the function which creates the object might say instead you should just pass the pointer to free. But only do this if the documentation says to!)
Here's two fundamental rules:
Each c file is compiled separately
When you #include a file, think of it as directly replacing the #include line with the contents of the file being included.
Therefore, you are compiling a piece of source code that looks like this:
struct A_s {
int a1;
};
typedef struct B_s {
A_t* a_f;
int b1;
} B_t;
void foo() {
B_t* b;
}
This code doesn't know what A_t is. You've never defined that in the code that's visible to the compiler.
A trivial way to fix this is to replace A_t with struct A_s.

struct X declared inside parameter list will not be visible outside of this definition or declaration [duplicate]

I just found a quirk in C that I find really confusing. In C it's possible to use a pointer to a struct before it has been declared. This is a very useful feature that makes sense because the declaration is irrelevant when you're just dealing with a pointer to it. I just found one corner case where this is (surprisingly) not true, though, and I can't really explain why. To me it looks like a mistake in the language design.
Take this code:
#include <stdio.h>
#include <stdlib.h>
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
Gives:
foo.c:6:26: warning: ‘struct lol’ declared inside parameter list [enabled by default]
foo.c:6:26: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
foo.c:8:16: warning: ‘struct lol’ declared inside parameter list [enabled by default]
To remove this problem we can simply do this:
#include <stdio.h>
#include <stdlib.h>
struct lol* wut;
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
The unexplainable problem is now gone for an unexplainable reason. Why?
Note that this question is about the behavior of language C (or possible the compiler behavior of gcc and clang) and not the specific example I pasted.
EDIT:
I won't accept "the order of declaration is important" as an answer unless you also explain why C would warn about using a struct pointer for the first time in a function argument list but allow it in any other context. Why would that possibly be a problem?
To understand why the compiler complains, you need to know two things about C "struct"s:
they are created (as a declared, but not yet defined, type) as soon as you name them, so the very first occurrence of struct lol creates a declaration
they obey the same "declaration scope" rules as ordinary variables
(struct lol { declares and then begins defining the structure, it's struct lol; or struct lol * or something else that does not have the open-brace that stops after the "declare" step.)
A struct type that is declared but not yet defined is an instance of what C calls an "incomplete type". You are allowed to use pointers to incomplete types, as long as you do not attempt to follow the pointer:
struct lol *global_p;
void f(void) {
use0(global_p); /* this is OK */
use1(*global_p); /* this is an error */
use2(global_p->field); /* and so is this */
}
You have to complete the type in order to "follow the pointer", in other words.
In any case, though, consider function declarations with ordinary int parameters:
int imin2(int a, int b); /* returns a or b, whichever is smaller */
int isum2(int a, int b); /* returns a + b */
Variables named a and b here are declared inside the parentheses, but those declarations need to get out of the way so that the the next function declaration does not complain about them being re-declared.
The same thing happens with struct tag-names:
void gronk(struct sttag *p);
The struct sttag declares a structure, and then the declaration is swept away, just like the ones for a and b. But that creates a big problem: the tag is gone and now you can't name the structure type ever again! If you write:
struct sttag { int field1; char *field2; };
that defines a new and different struct sttag, just like:
void somefunc(int x) { int y; ... }
int x, y;
defines a new and different x and y at the file-level scope, different from the ones in somefunc.
Fortunately, if you declare (or even define) the struct before you write the function declaration, the prototype-level declaration "refers back" to the outer-scope declaration:
struct sttag;
void gronk(struct sttag *p);
Now both struct sttags are "the same" struct sttag, so when you complete struct sttag later, you're completing the one inside the prototype for gronk too.
Re the question edit: it would certainly have been possible to define the action of struct, union, and enum tags differently, making them "bubble out" of prototypes to their enclosing scopes. That would make the issue go away. But it wasn't defined that way. Since it was the ANSI C89 committee that invented (or stole, really, from then-C++) prototypes, you can blame it on them. :-)
The compiler is warning you about a forward declaration of struct lol. C allows you to do this:
struct lol; /* forward declaration, the size and members of
struct lol are unknown */
This is most used when defining self-referencing structs, but it is also useful when defining private structs that are never defined in the header. Because of this latter use case, it is allowed to declare functions that receive or return pointers to incomplete structs:
void foo(struct lol *x);
However, just using an undeclared struct in a function declaration, as you did, will be interpreted as a local incomplete declaration of struct lol whose scope is constrainted to the function. This interpretation is mandated by the C standard, but it is not useful (there is no way to construct the struct lol to pass to the function) and is almost certainly not what the programmer intended, so the compiler warns.
This is because, in the first example, the struct is previously undefined and so the compiler tries to treat this first reference to that struct as a definition.
In general, C is a language where the order of your declarations matters. Everything you use should be properly declared in advance in some capacity, so that the compiler can reason about it when it's referenced in other context.
This is not a bug or a mistake in the design of the language. Rather, it's a choice that I believe was made to simplify the implementations of the first C compilers. Forward declarations allow a compiler to translate the source code serially in one pass (as long as some information such as sizes and offsets is known). If this weren't the case, the compiler would have be able to go back and forth in the program whenever it meets an unrecognized identifier, requiring its code emission loop to be much more complex.
I see this same warning before. My fix is to include the proper header file which contains the definition of the struct.
In addition to other answers, I would like to post a code example, which makes the problem more obvious. Please consider the following:
int testFunc(struct SomeStruct {int a; int b;} param1) // gcc: warning ...
{
return param1.a + param1.b;
}
int main(void)
{
struct SomeStruct params; // gcc: error: storage size of 'params' isn't known
params.a = 25;
params.b = 15;
return testFunc(params);
}
As you can see, the function declaration of testFunc is considered a valid C code (tested with GCC 12, Clang 15 and MSVC 19.32). However, you can't really use it because SomeStruct is only valid within the scope of the function, which is what compiler warns you about.
I've stumbled on this myself when working on my own C parser as the allowance of such syntax makes parser development easier as you can reuse the same implementation to parse struct declaration inside function parameter lists. It is surprising, however, that such bizarre syntax is still considered valid nowadays (as of C17) and instead of error you just get a warning.
Lookout for typos and DOUBLE CHECK your line numbers! I concat all my source files before compiling, so the line numbers from the source I am working in are meaningless. I have to take extra time to open up the concatted payload and examine it. So usually I don't and I just assume I know what line I am looking at from the console output message.
Example:
GCC Says:
EXAMPLE.C11:27:1: error: 'struct THIS_STRUCT_IS_OK' declared inside
parameter list [-Werror] ){
#include <stdio.h> //:for: printf(...)
struct THIS_STRUCT_IS_OKAY{
int whatever;
};
int LookingAtThisFunction(
struct THIS_STRUCT_IS_OKAY* arg
){
//: (Because you are not checking line numbers, you )
//: (assume you are looking here. But you are not. )
//: (Maybe you are concatenating all of your source )
//: (files together before compiling and line numbers )
//: (don't correspond to the original source and you )
//: (didn't examine your concatted source code payload?)
return( arg -> whatever );
}
//:You are not looking here because this is later in the
//:file, so the compiler would be complaining about the
//:FIRST usage of the struct, not the second one, you assume.
//:And you would be correct, if there wasn't a typo.
void WhereYouAreNotLooking(
struct THIS_STRUCT_IS_OK* arg
){
LookingAtThisFunction( arg );
}
int main( void ){
}
In summary: If you know what the error message means. And you swear to god
the compiler is broken because you already checked that...
1. Look for typos.
2. Make sure you are really looking at the correct line number.
I get that this is kinda stupid. But it had been scratching my head for
half an hour. So hopefully it helps someone who's already looked at the
obvious solutions.

Why GCC compiles this erroneous code?

I tried to compile something like:
struct A
{ int a;
struct B
{ int c;
};
};
Now when I compile this code the compiler gives me a warning message that:
declaration does not declare anything [enabled by default]
I know that I have not defined any instance of struct B. That will mean that I shall not be able to access variable c. Still compiler compiles this code with a warning. What's the whole point ? Why does not the compiler give a compilation error instead ?
ADDED Info:
The size of the struct A is equal to the size of int on my machine!!
Because you can do this:
struct A
{ int a;
struct B
{ int c;
};
};
int main()
{
struct A a = {1};
struct B b = {2};
return a.a + b.c;
}
Note:
you need a semicolon after declaring B, which your code is missing
this isn't particularly useful, but I suppose it might serve some documentary purpose (ie,to suggest a relationship or grouping between types)
in C++, the second variable would have type A::B, but C doesn't have the same scoping rules (all structs just belong to the global struct namespace, in effect)
As to the motivation for allowing it ...
struct Outer {
struct {
int b;
} anon;
/* this ^ anonymous struct can only be declared inside Outer,
because there's no type name to declare anon with */
struct Inner {
int c;
} named;
/* this ^ struct could be declared outside, but why force it to be
different than the anonymous one? */
struct Related {
double d;
};
/* oh no we have no member declared immediately ... should we force this
declaration to be outside Outer now? */
struct Inner * (*function_pointer)(struct Related *);
/* no member but we are using it, now can it come back inside? */
struct Related excuse;
/* how about now? */
};
Once you've allowed nested type declarations like this, I doubt there's any particular motivation to require there be a member of that type right away.
It's legal (but extremely bad style) to do:
struct A {
int a;
struct B {
int c;
};
};
struct B B_instance;
struct A A_instance;
And the compiler doesn't know about the later variables that use the struct types, so it really should not error out.
Generally, a warning means the code likely does not do what you intended but is legal in the language. The compiler is saying, “This is likely not what you really wanted to do, but I must allow you to do it because the language says it is allowed.” The compiler cannot give you an error for this code because the C standard permits it, so it must be allowed (unless you specifically ask for errors for such things, as by using GCC’s -Werror option to turn warnings into errors).
The C standard does not attempt to define everything that makes sense in a program. For example, these things are legal in C:
3;
if (x) then foo(); else foo();
x = 4*0;
The first statement has no side effects, and its return value is not used. But it is legal in C, since a statement may be just an expression. The second statement just calls foo(), so the if is pointless. In the third statement, multiplying by four is pointless.
It would be extremely difficult to write a C standard that prohibited all things that did not make sense. And it is certainly not worth the effort. So this is part of your answer: When the committee writing the C standard builds the language, do they want to spend a lot of time rewriting the technical specification to exclude things that do not make sense? Sometimes yes, if it seems valuable to avoid something that could cause serious bugs. But much of the time, it is just not worth their time and would complicate the specification unnecessarily.
However, compilers can recognize some of these things and warn you. This helps catch many typographical errors or other mistakes.
On the other hand, sometimes these constructions arise from unusual circumstances. For example, a program may have preprocessor statements that define struct A in different ways when building for different targets or different features. In some of those targets, it may be that the struct B member is not needed in struct A, so it is not declared, but the declaration of struct B (the type, not the object) remains present just because it was easier to write the preprocessor statements that way.
So the compiler needs to permit these things, to avoid interfering with programmers writing a wide variety of programs.
You are, in fact, declaring struct B here, but you are not declaring a variable of that type.
This is a warning, but one you should fix. Perhaps you meant:
struct A
{ int a;
struct B
{
int c;
} c;
};

Typedef and Struct in C and H files

I've been using the following code to create various struct, but only give people outside of the C file a pointer to it. (Yes, I know that they could potentially mess around with it, so it's not entirely like the private keyword in Java, but that's okay with me).
Anyway, I've been using the following code, and I looked at it today, and I'm really surprised that it's actually working, can anyone explain why this is?
In my C file, I create my struct, but don't give it a tag in the typedef namespace:
struct LABall {
int x;
int y;
int radius;
Vector velocity;
};
And in the H file, I put this:
typedef struct LABall* LABall;
I am obviously using #include "LABall.h" in the c file, but I am NOT using #include "LABall.c" in the header file, as that would defeat the whole purpose of a separate header file. So, why am I able to create a pointer to the LABall* struct in the H file when I haven't actually included it? Does it have something to do with the struct namespace working accross files, even when one file is in no way linked to another?
Thank you.
A common pattern for stuff like that is to have a foo.h file defining the API like
typedef struct _Foo Foo;
Foo *foo_new();
void foo_do_something(Foo *foo);
and a foo.c file providing an implementation for that API like
struct _Foo {
int bar;
};
Foo *foo_new() {
Foo *foo = malloc(sizeof(Foo));
foo->bar = 0;
return foo;
}
void foo_do_something(Foo *foo) {
foo->bar++;
}
This hides all the memory layout and size of the struct in the implementation in foo.c, and the interface exposed via foo.h is completely independent of those internals: A caller.c which only does #include "foo.h" will only have to store a pointer to something, and pointers are always the same size:
#include "foo.h"
void bleh() {
Foo *f = foo_new();
foo_do_something(f);
}
Note: The ISO C standard section on reserved identifiers says that all identifiers beginning with an underscore are reserved. So typedef struct Foo Foo; is actually a better way to name things than typedef struct _Foo Foo;.
Note: I have left freeing the memory as an exercise to the reader. :-)
Of course, this means that the following file broken.c will NOT work:
#include "foo.h"
void broken() {
Foo f;
foo_do_something(&f);
}
as the memory size necessary for actually creating a variable of type Foo is not known in this file.
Since you're asking a precise reason as to "why" the language works this way, I'm assuming you want some precise references. If you find that pedant, just skip the notes...
It works because of two things:
All pointer to structure types have the same representation (note that it's not true of all pointer types, as far as standard C is concerned).[1] Hence, the compiler has enough information to generate proper code for all uses of your pointer-to-struct type.
The tag namespace (struct, enum, union) is indeed compatible accross all translation units.[2] Thus, the two structures (even though one is not completely defined, i.e. it lacks member declarations) are one and the same.
(BTW, #import is non-standard.)
[1] As per n1256 §6.2.5.27:
All pointers to structure types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.
[2] As per n1256 §6.2.7.1:
two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are complete types, then the following additional requirements apply: [does not concern us].
In
typedef struct A* B;
since all pointers' interfaces are the same, knowing that B means a pointer to a struct A contains enough information already. The actual implementation of A is irrelevant (this technique is called "opaque pointer".)
(BTW, better rename one of the LABall's. It's confusing that the same name is used for incompatible types.)

Resources