Let's say we have two structs in a source file:
struct B {
int x;
};
struct A {
beta y;
};
In the equivalent header file we have these:
typedef B* beta;
typedef A* alpha;
Also, these function prototypes are defined at the header file:
printAplha(alpha);
compare(const beta, const beta);
In the main file, I have included the specific header file and the code looks like this:
alpha one, two;
printAlpha(one);
printAlpha(two);
//everything works fine up to here
compare(one->y, two->y);
At the last line of the code I am getting
main.c:37:20: error: dereferencing pointer to incomplete type
main.c:37:33: error: dereferencing pointer to incomplete type
I know I can use a wrapper function for compare, the arguments of which would be of type alpha (as the arguments of the compare function cannot be changed - it's a recursive one), but I would like to see if there is any other solution, and why is this happening.
Note: The struct definitions have been written into the source file for creating an opaque data type.
You're trying to declare an opaque data-type for struct A and struct B using the typedefs, but at the same time you're trying to access the fields using such an opaque type.
You can only do one of the above, not both simultaneously.
The solution is to either expose the complete struct definition or provide helper methods which will help access the specific fields. The implementation of the helper methods will again need to have access to the complete structure definition.
There's certainly no "encryption" going on in what you're doing, but it is making it impossible for your example code to see the implementations of those structures. If you want to access fields in a structure, you need to make the complete structure definition visible to that translation unit. Otherwise, it's an incomplete type, just like the error message says.
Related
I have several C source and header files, with a .h file for each ADT.
One of them is called Tournament. When I try to malloc memory for tournament inside tournament.h no problem happens, but when I do it in a different c file it gives me the following error
"incomplete type is not allowed"
Here is the way tournament is defined in tournament.h
typedef struct tournament_t *Tournament;
ps: some people say it's a bad thing to typedef a struct but I have to do it since the instructors want it.
And this is how it is in tournament.c and I have no problems with it
struct tournament_t
{
//fields
};
Tournament tournamentCreate()
{
Tournament new=malloc(sizeof(*new));
if(!new)
{
return NULL;
}
//I don't get any error here
}
However, in a file called chess.c, this is what happens:
#include "tournament.h"
static Tournament copyTournament(Tournament tournament)
{
if (!tournament) {
return NULL;
}
Tournament copy = malloc(sizeof(*copy));//here I get the error
if (!copy)
{
return NULL;
}
}
PS: the last function has to be static because again the instructor wants it to be.
If you need any more information to solve it, please tell me.
typedef struct tournament_t *Tournament; serves as a forward declaration of the struct. At this point in the header file, this contents of the struct is unknown to the compiler. It means that you need to write the struct definition elsewhere or the struct will rename unknown - an incomplete type.
You then place the struct definition in tournament.c. This means that the struct contents are now visible to the compiler inside that translation unit. Translation unit meaning that .c file and all the headers it includes.
This in turn means you are free to use the struct members inside tournament.c. But they will not be visible to chess.c. Because it is a different translation unit. All it can see is the forward declaration in the header, so it remains an incomplete type to chess.c.
If you had written the typedef as typedef struct tournament_t Tournament; without the pointer declaration, then chess.c wouldn't be able to even declare objects of this type, because it doesn't know how the struct is built. It can however declare pointers to an object of incomplete type - you can have a pointer without knowing the details of what it points at.
This is all likely by design, this method is known as "opaque type" and is how you design private encapsulation in C, to prevent the rest of the program from accessing members of a struct.
some people say it's a bad thing to typedef a struct but I have to do it since the instructors want it.
Using typedef or not in combination with structs is 100% subjective coding style and there's no right or wrong there. However, using pointers together with typedef is often problematic, since it can trick the programmer into thinking they have a normal object and not a pointer. In your cases, it tricks you into believing you have access to the struct.
Since it's an incomplete type you can't declare an object of it outside tournament.c. Nor can you use sizeof on such an object. That's what the compiler error is about.
You should solve this by having tournament.h providing a function that copies objects, which in turn should be implemented in tournament.c. Note how "opaque type" is forcing you to do proper program design, instead of having non-related code in some other unrelated file doing things it shouldn't.
I'm quite rusty in C, but I think I'm having issues understanding the proper usage of using typedefs in headers, defining the actual struct's structure in the implementation file, and then using the struct in a third file.
I wrote a queue data-structure that has a type defined as such:
typedef struct queue
{
int count;
qnode_t *head;
qnode_t *tail;
} queue_t;
Where qnode_t is a struct that's only used within the queue's implementation file.
Within my header I have this:
typedef struct queue queue_t;
When using this queue_t type within another file I'm attempting to get the queue's length like this:
queue_t *work_queue;
...
int length = work_queue->count;
However, on that line where I'm looking up count I get the compiler error:
dereferencing pointer to incomplete type
I've been doing a lot of research about how to properly define types in C, but I think I just keep confusing myself more and more instead of getting clarity since many examples are either conflicting with other resources or are too simplified for me to put to practical use.
Would I be getting this error because the 'count' variable within the struct isn't defined there? If this is the case, then can I define the struct in BOTH the implementation and header? If so, can the header only have the count variable defined since the head & tail should be hidden/private? (I miss OOP) Should I just be making another function that takes a queue_t* and returns its length as size_t?
you can only dereference defined types, not declared types.
Type declarations are useful to type-check opaque pointers, but
object fields are not visible, cannot be accessed. You need to move the typedef into the header
to access fields of your queue object.
Edit: from the questions/answers below:
Yes, two identical struct definitions are seen as the same typedef. You could omit fields if you never had both definitions in the same source file, but don't do it, that leads to bugs and maintenance confusion. Better to use a naming convention eg names starting with underscores are internal.
The convention is to define the struct in the header then include the same header in the implementation file. This keeps the published layout in sync with the implementation
It is not possible in C to dereference any pointer unless the compiler has access to complete information about the type of what is pointed at. For struct pointers, that means a complete struct definition is needed.
So, when compiling the code that is complaining about an incomplete type, the compiler needs to have visibility of the complete definition of the struct type, not just the typedef of the pointer.
I have a header and a sample application using this header, all in C, I get almost all the logic of this software except for this; this the interesting part of the header:
struct A;
typedef struct A A;
in the C application this A is only used when declaring a pointer like this
A* aName;
I'm quite sure that this is a solution for just including A in the scope/namespace and give just a name to a basically void pointer, because this kind of pointer is only used to handle some kind of data, it is more like some namespace sugar.
What this could be for?
You're correct that it's like a void pointer, in that void is an incomplete type, and in this file A is also an incomplete type. About all you can do with incomplete types is pass around pointers to them.
It has one advantage over void* in this file, that it's a different and incompatible type from some other bit of code that has done the same thing with B. So you get a bit of type safety. If A is windowHandle and B is jpgHandle, then you can't pass the wrong one to a function.
It has an advantage over void* in the .c file that defines the functions that accept an A* -- that file can contain a definition of struct A, and give A whatever members it wants, that the first file doesn't need to know about.
However, you say there are no other mentions of A in any header file, which means there are no functions that accept or return it. You also say that the only use of A in your source file is to declare pointers -- I wonder where the values of those pointers come from, if any.
If all that happens if that someone defines an uninitialized A* and never uses it, then clearly this is a remnant of some old code, or the start of some code that never got written, and it shouldn't be in the file at all.
Finally, if the real type is called something a bit less stupid than A, then the name might give a clue to its use.
I assume struct A is a forward declaration. It most likely is defined in one of the .c-files.
Doing so struct A's members are private to the module defining it.
This is an example of an opaque pointer, which is useful for passing handles. See http://en.wikipedia.org/wiki/Opaque_pointer for some further info. What may be interesting here from a C++ perspective, is the notion that you can define a class with a member that is a pointer to an (as yet) undefined struct. Although this struct is thus not yet defined in the header, in some later cpp implementation this struct is given body, and the compiler does the rest. This strategy is also called the Pimpl idiom (more of which you will find LOTS on the internet). Microsoft discusses it briefly at http://msdn.microsoft.com/en-us/library/hh438477.aspx.
I am just getting back into the C programming realm and I am having an issue that I think is linker related.
I am using cmake for the first time as well, so that could be adding to my frustration.
I have included a third party header file that contains a typedef that my code is trying to use, and it has this line:
typedef struct pcap pcap_t;
so my code has
pcap_t *var;
//later.....
var->fd;// this line throws the error
which throws the
error: dereferencing pointer to incomplete type
So am I just missing another include file, or is this a linker issue? I am building this code in QtCreator and using cmake. I can dive on a_t to see that typedef declaration in the included header, but I can't seem to dive on "struct a" itself to see where it's coming from.
Thanks
edited the code above to reflect that I am using the pcap libraries
so i have included in my source file's header file the following lines
#include <net/bpf.h>
#include <pcap/pcap.h>
so I guess between these two includes, I am missing the defintion of the pcap structure. Where can I find it?
Thanks
The typedef statement does two things. It declares the existence of something of type struct a. It also declares that a_t is an alias for struct a. Declaring the existence of a type without any information to determine its size is called by the C language an incomplete type. The declaration is colloquially referred to as a forward declaration, and the type is colloquially referred to as opaque to those parts of the code that never get to see the type's definition.
typedef struct a a_t;
a_t *var;
The C language allows pointers to an incomplete type to be defined. A pointer to an incomplete type is not itself incomplete, since a pointer to a type is the same size as a void pointer. But, your code then attempts to dereference the pointer:
var->member;
Since there is no definition of struct a available, the compiler has caught an error in your program, and is telling you about it. It is not a linker issue, but a semantic error in your program.
An opaque type is a way to hide implementation details from the user of the type. That is, it is C's way of providing an interface:
typedef struct a a_t;
a_t *a_create ();
void a_destroy (a_t *);
int a_get_member (a_t *);
void a_set_member(a_t *, int);
Then, in your code, you are expected to use the interface.
a_t *var = a_create();
a_set_member(var, 10);
int m = a_get_member(var);
a_destroy(var);
The source file that implements the interface would actually define what struct a looks like. Since you said you had no definition to reference in your debugger, this likely means you did not provide a definition anywhere in your program.
Edit: It seems you are trying to use the packet capture library. You will need to include the <pcap.h> header file to your code, and link with -lpcap. If the header file or library does not exist, you will need to install the packet capture development package for your OS. The <pcap.h> has made a typedef for pcap_t already, and it is intentionally opaque. So you will have to use the interfaces the header file defines to access the information you want.
Though I rarely write C code, I often see it (mostly due to books in my field having it as sort of reference language for algorithm examples) and something has been bugging me for a while about the way variables/parameters are declared. The best example would be this List with a twist example, about a particular implementation of Linked List used in Linux kernel (sorry, I had a link to a blog post originally, but apparently the blog post has been deleted, I copied code from my browser's cache).
struct blog {
...
struct ls posts;
};
struct post {
...
struct ls blog_posts;
};
void delete_blog(struct blog *blog) {
...
struct post *p;
ls_for_each(&blog->posts, p, blog_posts) {
free(p);
}
free(blog);
}
What bugs me is the fact that they keep repeating the keyword struct everywhere. I mean things like ls, blog, post are declared as structs, so what is the point of saying it is a struct every time you declare a variable or a function parameter of that type? What does this tell the compiler that it can't infer from the fact that the thing you are instantiated has been defined as a struct?
Well, it's because if there isn't a typedef, that's the only way to refer to the struct.
In C, if you have:
struct thing {
// stuff here
};
and you want to have a variable of that type, you need to either:
use struct thing as the type specifier
make a typedef like typedef struct thing thing_t; and use thing_t as the type specifier.
(C++ is different in this respect.)
struct tags are in a different namespace than usual identifiers. So the struct keyword is necessary to specify that. A famous example is in POSIX where you have a struct stat and a function stat.
It is just the way the syntax is...
C is a quite old language, and it purposely created a syntax which differentiated between the typed which could be represented directly by machine instructions and those which were more complex and spanned several memory locations.
"Typedef" was added to the language to allow the creation of shorter names which didn't included the struct, however the full struct syntax is used - and specifically is used in historical context where the original definition of a system structure is defined as "struct" without a corresponding typedef short form.
As comparison C++ which is a much later language, allows a class/struct to be referred to by just the class/struct name regardless of whether it was defined with a typedef.
So as questions goes, the answer is that it just is like that because it is...
EDIT: Just looking at your example code, there is one notable case where struct adds something to the compiler behavior -- in most cases a type has to be defined before it can be used in a another declaration -- except for when you refer to a struct sometype* (i.e. a pointer to a struct) in which case the compiler is happy to have the sometype defined after the use.
so
struct post {
struct post *nextpost;
struct post *prevpost;
...
};
becomes possible, as post is not defined until the closing bracket of the struct.
struct is part of the type declaration.
If a function takes an argument (/parameter), then the type of that argument must be declared. How could you declare that that argument is a struct if you cannot use the word struct ?
Many modern C libraries are systematically typedef-ing their struct and use some naming convention. For example gtk/gtkalignment.h has:
typedef struct _GtkAlignment GtkAlignment;
typedef struct _GtkAlignmentPrivate GtkAlignmentPrivate;
typedef struct _GtkAlignmentClass GtkAlignmentClass;
My own habit is to name foo_st the struct and foo_t the type, so I often code
typedef struct foo_st foo_t;
And I would use union foo_un if it where a union.