I have a strange problem in C about including header files.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "location.h"
int waste_new_line();
int main()
{
location *crossroads = malloc(sizeof(*crossroads));
...
location.h
typedef struct Location_Struct location;
location.c
typedef struct Location_Struct {
int ID;
char *name;
char *description;
} location;
int setup_location(location* l, char* name)
{
...
Now this isn't working because
location *crossroads = malloc(sizeof(*crossroads));
is throwing an error:dereferencing pointer to incomplete type meaning that it can see the contents of location.h, yet it doesn't seem to be aware of location.c...
I've looked around and all the tutorials I've seen say that the linker will link both files together.
EDIT:
I have altered the code to include an initializer inside location.c as so:
main.c
...
#include "location.h"
int waste_new_line();
int main()
{
location *crossroads = initialize_location();
....
location.h
typedef struct Location_Struct location;
location* initialize_location();
location.c
...
typedef struct Location_Struct {
int ID;
char *name;
char *description;
} location;
location* initialize_location(location* l)
{
return malloc(sizeof(location));
}
...
This is still throwing the same error, yet only when I try and access the members of crossroads using:
crossroads->description
this will throw the deferencing to incomplete type error.
EDIT 2: For now I've decided to just put the struct definition in the header file...
This behaviour is expected. When you #include "location.h", only the header file is visible to the compiler. The location.c file comes along later, at link time.
You have two options:
Add a function, which you declare in location.h and define in location.c, which does the necessary malloc and returns a pointer.
Move the full definition of the struct to the header file.
The main file knows about a struct called Location_Struct (and a typedef). It has no idea how big it is, thus you can't apply sizeof to it.
Since you are effectively hiding the layout and the implementation of Location_Struct it makes sense to provide a "constructor" that allocates it.
EDIT
It seems I have to mention that by "constructor" I mean an ordinary function that has access to the implementation of the structure and can allocate and possibly pre-populate the object.
You need to put the definition of Location_Struct in the header file location.h. The compiler would not "see" the other source file (unless it were #include'd, which would not typically be a good idea).
Related
I'm a bit new to C and I'm having a bit of trouble with a project I'm currently working on. Essentially I have the following files: main.c, alarm.c, alarm.h
I have a struct declaration in alarm.c that looks like:
#define STRLEN 150;
struct alarmparams
{
char time[STRLEN];
char duration[STRLEN];
char snooze[STRLEN];
char port[STRLEN];
};
In main.c I have:
#include <stdio.h>
#include <string.h>
#include "alarm.h"
int main(int argc, char *argv[])
{
struct alarmparams params;
printf("%s, %s\n", params.time, params.duration);
}
And in alarm.h I have:
struct alarmparams;
Right now when I go to compile I get the following error:
error: storage size of ‘params’ isn’t known
I've looked through other posts regarding this error, so I have done a bit of research on this already. I've also tried some of the suggested solutions and it's either I get the exact same error or I got more on top of it. I'm at a lose as to how to fix this.
Is there something I'm missing? Did I declare something incorrectly?
In general should structs be declared in the header file or the c file? Or does it even matter? What's the different between:
struct foo {...};
and
typedef struct foo {...};
struct alarmparams;
is the declaration of an incomplete type. You can create a pointer to an object of this type but you cannot declare an object of this type or take its size until it has been completed. You have to make its complete declaration visible in main.c to declare an object of its type.
If you use the type in both alarm.c and main.c, just declare it in alarm.h and include alarm.h in main.c.
For you second question, the difference between:
struct foo {...};
and
typedef struct foo {...} foo_;
is in the latter case you also declare an alias foo_ for the type name struct foo.
You have to declare the structure in the header file alarm.h.
At the moment, when you include alarm.h, the code in main doesn't see the structure composition, all it sees is struct alarmparams;, so it doesn't know how long it is. How can you allocate space for something that you don't know how much space it takes?
typedef struct foo { ... }; is invalid: typedef expects you to provide an alias for a type. typedef struct foo { ... } foo_t; would be correct.
typedef is a storage class specifier, thus, you can think of it as any other regular declaration. Imagine you want an alias foo for the type bar: just declare a variable of type bar and call it foo. Now, prepend a typedef keyword behind, and you are done. Even complicated typedefs can be easily understood with this simple approach. Since struct foo { ... }; would be an invalid declaration for a variable (no name is provided), so is typedef struct foo { ... };.
In general, declare structures in the header file when you will reuse them in other source files. If you don't plan on doing so, declaring them on the .c file should be fine.
In addition to the other answers, the value of STRLEN must be known at compile time (it most likely is in this case, but just in case).
this error seems very easy to fix but i've been trying and have no clue.
So i have three files:
symtable.h:
typedef struct symbolTable *SymTable_T;
symtablelist.c:
#include "symtable.h"
struct Node{
char* key;
void* value;
struct Node* next;
};
struct symbolTable{
struct Node* head;
int length;
};
SymTable_T SymTable_new(void){
/* code */
}
And main.c:
#include "symtable.h"
int main(int argc, const char * argv[]) {
// insert code here...
SymTable_T emptyTable = SymTable_new();
emptyTable->length = 3; <------- ERROR
return 0;
}
I'm getting error: Incomplete definition of type "struct symbolTable"
Can anyone please give me a hint?
The reason i declare my struct in my source file is that i will have another implementation for the header file. so is there another way to fix my bug beside moving my struct declaration?
You can't access the members directly with an opaque pointer - if you keep the implementation in a separate source file, you'll have to access all the members via your interface, and not directly mess with the struct.
For instance, add this to symtable.h:
void SymTable_set_length(SymTable_T table, int len);
this to symtablelist.c:
void SymTable_set_length(SymTable_T table, int len)
{
table->length = len;
}
and in main.c change this:
emptyTable->length = 3;
to this:
SymTable_set_length(emptyTable, 3);
although in this specific case passing the length as an argument to SymTable_new() is an obviously superior solution. Even more superior is not letting the user set the length of a linked list data structure at all - the length is the number of items in it, and it is what it is. It would make no sense to, for instance, add three items to the list, and then allow main.c to set the length to 2. symtablelist.c can calculate and store the length privately, and main.c can find out what the length is, but it doesn't make much sense for main.c to be able to set the length directly. Indeed, the whole point of hiding the members of a struct behind an opaque pointer like this is precisely to prevent client code from being able to mess with the data like that and breaking the data structure's invariants in this manner.
If you want to access the members directly in main.c, then you have to have the struct definition visible, there is no alternative. This will mean either putting the struct definition in the header file (recommended) or duplicating it in main.c (highly unrecommended).
In typedef symbolTable *SymTable_T;, you refer to a non-existent type symbolTable. In C (unlike C++) the type is named struct symbolTable. (Note: the question has changed to fix this since answering it.)
There's a second problem. In main.c the code will need to be able to see the definition of struct symbolTable for you to be able to refer to fields of emptyTable. At the moment, the definition is hidden in a .c file... it should be moved to the header.
I'm a bit new to C and I'm having a bit of trouble with a project I'm currently working on. Essentially I have the following files: main.c, alarm.c, alarm.h
I have a struct declaration in alarm.c that looks like:
#define STRLEN 150;
struct alarmparams
{
char time[STRLEN];
char duration[STRLEN];
char snooze[STRLEN];
char port[STRLEN];
};
In main.c I have:
#include <stdio.h>
#include <string.h>
#include "alarm.h"
int main(int argc, char *argv[])
{
struct alarmparams params;
printf("%s, %s\n", params.time, params.duration);
}
And in alarm.h I have:
struct alarmparams;
Right now when I go to compile I get the following error:
error: storage size of ‘params’ isn’t known
I've looked through other posts regarding this error, so I have done a bit of research on this already. I've also tried some of the suggested solutions and it's either I get the exact same error or I got more on top of it. I'm at a lose as to how to fix this.
Is there something I'm missing? Did I declare something incorrectly?
In general should structs be declared in the header file or the c file? Or does it even matter? What's the different between:
struct foo {...};
and
typedef struct foo {...};
struct alarmparams;
is the declaration of an incomplete type. You can create a pointer to an object of this type but you cannot declare an object of this type or take its size until it has been completed. You have to make its complete declaration visible in main.c to declare an object of its type.
If you use the type in both alarm.c and main.c, just declare it in alarm.h and include alarm.h in main.c.
For you second question, the difference between:
struct foo {...};
and
typedef struct foo {...} foo_;
is in the latter case you also declare an alias foo_ for the type name struct foo.
You have to declare the structure in the header file alarm.h.
At the moment, when you include alarm.h, the code in main doesn't see the structure composition, all it sees is struct alarmparams;, so it doesn't know how long it is. How can you allocate space for something that you don't know how much space it takes?
typedef struct foo { ... }; is invalid: typedef expects you to provide an alias for a type. typedef struct foo { ... } foo_t; would be correct.
typedef is a storage class specifier, thus, you can think of it as any other regular declaration. Imagine you want an alias foo for the type bar: just declare a variable of type bar and call it foo. Now, prepend a typedef keyword behind, and you are done. Even complicated typedefs can be easily understood with this simple approach. Since struct foo { ... }; would be an invalid declaration for a variable (no name is provided), so is typedef struct foo { ... };.
In general, declare structures in the header file when you will reuse them in other source files. If you don't plan on doing so, declaring them on the .c file should be fine.
In addition to the other answers, the value of STRLEN must be known at compile time (it most likely is in this case, but just in case).
The function getManager creates a Manager struct and returns a pointer to it from the type ManagerP (This function works ok). The definitions are like this :
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
//My little code (that does the problem) is this (it's inside main):
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"
Can you please help me finding the problem ? I don't understand what this error mean.
Thanks.
EDIT:
Thanks but I just noticed a problem.
These lines are inside "Manager.c".
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
In my main file I do include "Manager.h" that has some more definitions.
I just checked and when I'm moving the two typedefs code (written above) to the main file, everything works properly. But I need these typedefs to be inside "Manager.c" (and then I still get a "dereferencing pointer to incomplete type" error. So what is the problem ??
Edit #2 :
Ok I'm posting the three files. When I compile those I get the error :
"GenSalary.c:9:21: error: dereferencing pointer to incomplete type"
These are the files :
// *Manager.h* :
#ifndef MANAGER_H
#define MANAGER_H
#define MAX_NAME_LENGTH 30
typedef struct Manager *ManagerP;
ManagerP getManager(int ID, const char name[], double paycheck,
double attract, int numberOfStudentsInSchool);
#endif
// *Manager.c* :
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"
#define MAX_PRINT_LENGTH 1000
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
ManagerP getManager(int ID, char const name[], double paycheck,
double attract, int numberOfStudentsInSchool)
{
ManagerP retVal = (ManagerP) malloc(sizeof(struct Manager));
if (retVal == NULL)
{
fprintf(stderr, "ERROR: Out of memory in Manager\n");
exit(1);
}
retVal->ID = ID;
strcpy(retVal->name, name);
retVal->paycheck = paycheck;
retVal->attract = attract;
retVal->numberOfStudentsInSchool = numberOfStudentsInSchool;
return retVal;
}
// *GenSalary.c* :
#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"
int main()
{
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"
return 0;
}
I compile it using gcc -Wall GenSalary.c Manager.c -o GenSalary and i'm getting :
GenSalary.c:9:21: error: dereferencing pointer to incomplete type
NOTE : I CAN'T CHANGE THE MANAGER FILES (THEY BELONG TO EXERCISE)I CAN CHANGE ONLY MAIN.
Thanks for helping !
As written, getManager looks like it intends the returned pointer to be opaque. If that is the case, it would be usual to provide functions for anything the caller should be able to do. For example:
manager.h
...
typedef struct Manager *ManagerP;
ManagerP getManager(int ID, const char name[], double paycheck,
double attract, int numberOfStudentsInSchool);
int getManagerID(ManagerP);
manager.c
...
int getManagerID(ManagerP m) { return m->ID; }
gensalary.c
...
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = getManagerID(manToFind);
The alternative is to move the definition of your struct into the header, where everything can see it (at the moment it is forward-declared in the header, but only manager.c know what is inside).
The code below works fine with gcc -Wall -pedantic -o test test.c. I am unsure, however, that hiding pointer types using typedefs has any real advantages to readability. The error must come from somewhere in the context of your code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Manager
{
int ID;
char name[42];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
ManagerP getManager(int x, char *y, double z, double q, int p)
{
ManagerP foo = malloc(sizeof(Manager));
foo->ID = x;
strncpy(foo->name, y, 42);
foo->numberOfStudentsInSchool = p;
foo->paycheck = z;
foo->attract = q;
return foo;
}
int main(void)
{
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = manToFind->ID;
printf("Found ID: %d\n", foundId);
return 0;
}
From your own edit:
I just checked and when I'm moving the two typedefs code (written
above) to the main file, everything works properly. But I need these
typedefs to be inside "Manager.c"
You need to include these definitions for it to work, as you've found. Put them in "Manager.h" and include "Manager.h" in both your main file, and in "Manager.c".
EDIT: From your code, you need to include the typedef of the actual struct in the header file, as well, not just the typedef of the pointer, so move this:
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
out of "Manager.c", and put it immediately before the typedef of ManagerP. Otherwise, all the main file sees is the declaration of the pointer, and it has no information of what the struct actually contains, hence the "incomplete type" error you're getting.
EDIT 2: If you "CAN'T CHANGE THE MANAGER FILES" as you say, then it's a bit of a silly question, since you can't apply the best answer, but if that actually is true, then you'll just have to copy and paste the struct definition into "GenSalary.c" (or into a new, user-created header file, if you need to use it in other files, too), because that file needs it. Defining the struct separately in both "GenSalary.c" and "Manager.c" is a bad idea for lots of reasons, but it is perfectly legal C, and it'll work (that's all that's happening under the hood when you #include a header file, anyway).
The line of doing the typedef for ManagerP will compile since it is a pointer declaration however since the struct Manager is in the file Manager.c and is not available to GenSalary.c the compiler is unable to know what the struct Manager looks like.
So the include file Manager.h needs to have the following lines of code.
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
Then any source file that includes Manager.h will have the definition of the Manager typedef as well as the ManagerP typedef. And when the ManagerP is dereferenced, the compiler will know how to access the various parts of the Manager struct.
Edit: Other considerations
You mention that this is an exercise of some kind so I would like to note that the way this is being done, the struct in a file and the only thing exposed is a pointer to the struct, is a mechanism often used to hide struct details. The goal of this technique is to provide a pointer to an object within a library, the struct in this case, however the person using the library is not to access any of the struct members or to do anything other than pass the pointer to other functions in the library.
So it may be that the point of this exercise is to not access any of the struct members.
When you create a pointer to a type, the compiler does not need to know what that type looks like, because all pointers are the same size (4 or 8 or however many bytes). However, if you attempt to dereference that pointer, the compiler must know what the type looks like in order to calculate memory offsets and perform other tasks. Since in your original cpp file the type Manager is not defined, only declared, the compiler cannot determine what memory offset it needs to use before it can reach the ID field. (A type like this is often called opaque.) Thus the compiler informs you that the type is incomplete.
The same issue would occur if you attempted to create a variable of type Manager directly, because the compiler does not know how much memory is required to be set aside for this variable. You could malloc a pointer to Manager, but if you tried to do sizeof(Manager), it would fail.
In order for this to work, the compiler needs to know what the type looks like at the point where you attempt to dereference the pointer. Thus, the struct definition must be placed within the main cpp file, or within any of the headers which are included by that cpp file.
Consider the following struct defined in ModuleA:
typedef struct{
int A;
int B;
int C[4];
}myStructType;
myStructType MyStruct;
If I wanted to use this struct from ModuleB, then I would declare the struct in the ModuleA header like this:
extern myStructType MyStruct;
So far, so good. Other modules can read and write MyStruct by including the Module A header file.
Now the question:
How can I declare only part of the struct in the Module A header file? For example, if I wanted ModuleB to be able to read and write MyStruct.C (or, to make things a bit easier, perhaps MyStruct.A or MyStruct.B), but not necessarily know that it's in a struct or know about elements A and B.
Edit: I should probably also specify that this will go in an embedded system which does basically all of its memory allocation at compile time, so we can be extremely confident at compile time that we know where MyStruct is located (and it's not going to move around).
Edit2: I'll also clarify that I'm not necessarily trying to prevent other modules from accessing parts of the struct, but rather, I'm attempting to allow other modules to access individual elements without having to do MyStruct.Whatever because other modules probably only care about a single element and not the whole structure.
You would have to encapsulate it, i.e. make a private variable such as:
static myStructType the_struct;
in some C file, and then provide an API to get access to the parts:
int * getC(void)
{
return the_struct.C;
}
this would then let other C files get access to an integer array by calling
int *some_c = getC();
some_c[0] = 4711;
or whatever. It can be made "tighter" by being more explicit about the length of the returned array of course, I aimed for the minimal solution.
While in theory there might be some problems with the cleanliness of this solution (e.g. structure alignment), in practice it usually works if it compiles and if it doesn't compile, you can alter the structures to make it compile:
#include <stddef.h>
#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]
// You keep this definition private to module A (e.g. in a .c file):
typedef struct
{
int A;
int B;
int C[4];
} PrivateStruct;
// You expose this definition to all modules (in an .h file):
typedef struct
{
char reserved[2*sizeof(int)];
int C[4];
} PublicStruct;
// You put these in module A (in a .c file):
C_ASSERT(sizeof(PrivateStruct) == sizeof(PublicStruct));
C_ASSERT(offsetof(PrivateStruct,C) == offsetof(PublicStruct,C));
int main(void)
{
return 0;
}
In the public .h file you can lie to the world about the global variable type:
extern PublicStruct MyStruct; // It's "PrivateStruct MyStruct;" in module A
If the two structure definitions go out of sync, you get a compile-time error (match, mismatch).
You will need to manually define the size of the reserved part of PublicStruct, perhaps by trial and error.
You get the idea.
To make the long story short — you can't. To make it a bit longer, you can't reliably do it.
You could try to use a kind of getter:
in ModuleA:
typedef struct{
int A;
int B;
int C[4];
}myStructType;
myStructType MyStruct;
int getA()
{
return MyStruct.A;
}
and so on.
Instead switch over to c++
You can't do exactly what you've described but it's common to have a struct used as a header, which is contiguous with a buffer which has it's internals only known to a particular module.
It's fairly obvious what this struct is the header for, but it still works as an example:
typedef struct _FILE_NOTIFY_INFORMATION {
ULONG NextEntryOffset;
ULONG Action;
ULONG NameLength;
ULONG Name[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
This struct (from Microsofts NativeSDK) is designed to be the header of a variable length buffer. All modules can work out how long the buffer is by looking at NameLength but you could use this method to store anything in the buffer which goes with it. That might only be known by a particular module with the others just using the length to copy it etc..
If it not for hiding but for structuring, then do structure it. For example like so:
moduleA.h:
typedef struct{
int A;
}myStructModuleAType;
extern myStructModuleAType myStructModuleA;
moduleA.c:
myStructModuleAType myStructModuleA;
moduleB.h:
typedef struct{
int B;
}myStructModuleBType;
extern myStructModuleBType myStructModuleB;
moduleB.c:
myStructModuleBType myStructModuleB;
main.h:
#include "moduleA.h"
#include "moduleB.h"
typedef struct{
myStructModuleAType * pmyStructModuleA;
myStructModuleBType * pmyStructModuleB;
int C[4];
}myStructType;
extern myStructType myStruct;
main.c:
#include "main.h"
myStructType myStruct;
myStructType myStruct = {
.pmyStructModuleA = &myStructModuleA
.pmyStructModuleB = &myStructModuleB
};