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.
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.
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.
I've got two header files, each requiring a type defined in the other. When I try to compile, I get an error regarding an unknown type name. (If I provide only struct declarations and not definitions, I get an incomplete-types error.) What's a solution that will let me share these structs properly?
Right now, my code looks rather like the following (just imagine the #ifndef preprocessor directives etc.):
<headerA.h>
#include "headerB.h"
typedef struct {
mytypeB myB;
} mytypeA;
<headerB.h>
#include "headerA.h"
typedef struct {} mytypeB;
void foo( mytypeA * myA);
You should forward-declare the struct mytypeA instead of including headerA.h:
Inside headerB.h:
struct mytypeA; // <<<--- Forward declaration
void foo(struct mytypeA* myA);
This works because you are not using the actual mytypeA, only a pointer to it. You cannot pull the same trick with headerA, because mytypeA includes the actual mytypeB.
You can forward declare a structure without needing to define the whole thing.
These SO questions might help you since it is related to your question.
undefined C struct forward declaration
How to declare a structure in a header that is to be used by multiple files in c?
gcc 4.4.4 c89
I have this in my header file.
port.h
struct struct_tag;
int initialize_ports(struct_tag *port);
In my implemenation file I have this:
port.c
typedef struct struct_tag {
int port_id;
} Port_t;
And in my driver.h file, I have the following:
#include "port.h"
int initialize_ports(struct_tag *port)
{
port = malloc(sizeof *port);
/* do checking here */
}
I have forward declared the structure, as I want to hide the internal elements.
However, I am getting the following error on my initialize_ports in the header file:
expected ‘)’ before ‘*’ token
I am just wondering how can I forward declare and be able to pass the structure as a parameter?
Many thanks for any advice,
You should use:
int initialize_ports(struct struct_tag *port);
^^^^^^
Also, forward declarations give you an incomplete type which you don't know the size of. If you need to allocate a struct struct_tag you need to include the full definition for it. Alternatively you could use some create_struct_tag() function if you want to make it fully opaque.
As other answers have noted, you could change struct_tag to struct struct_tag in the prototype. Another way of getting your code to compile is to write
typedef struct struct_tag struct_tag;
in place of your existing struct struct_tag; (i.e. combine the typedef with the forward definition). That then does allow you to write
int initialize_ports(struct_tag *port)
without compile failures. However, this is still not quite what you want, because the caller can neither allocate a local variable of this type, nor malloc() one - because they don't know the size.
Other answers have suggested that you should open up the definition of the structure. That's generally not the right answer - because it removes the abstraction layer you're trying to create. Much better to have functions (in the port.c, i.e. the library that does know about the internals) such as:
struct_tag *create_port(...);
void free_port(struct_tag *port)
i.e. to create and free the structures - and indeed for other operations (such as reading from / writing to the structure) too.
You'll get an error as you don't KNOW the size of "port" as all it has to go on is the forward declaration.
In summary you are best off not using a forward declaration here unless you also set a constant value that is the sizeof "struct_tag" ... You would most likely be best off just fully declaring it.
The sizeof operator is evaluated at compile time not runtime, so at the line:
port = malloc(sizeof *port);
the compiler has no information regarding the size of the structure.
Solutions include:
fully define the type in the header file.
define initialize_ports() in port.c after the struct is fully defined.
have initialize_ports() call a function defined in ports.c to get the size of Port_t at run-time.
In any case you should not define initialize_ports() in the header file driver.h unless your compiler supports the inline or _inline keyword and you use it. Such usage would however render the code non ISO C compliant, and therefore less portable, however due to C++'s standard support for the keyword, you are likely to find it as an extension in most C tool-chains that include C++ compilation, so long as you do not use excessively strict compliance options.
However the error message you are getting is for a different reason. Unlike C++ in C struct_tag alone does not represent a type (if it did, you'd not have needed the typedef!), you must use the struct keyword.