I have a list of checkpoints and then a run a function. I originally built this list in that function, but now I have to build it outside. The problem is that I cannot include checkpoint.h in the class that implements that function because checkpoint.h returns a structure of the type of that class. The initial list was declare in class.c globally. How can I transfer the list created outside into class so I can use it?
So I have this header, turing_machine.h:
#ifndef __TURING_MACHINE__
#define __TURING_MACHINE__
#include "tape.h"
#include "alphabet.h"
#include "symbol_table.h"
...
#endif
and the checkpoint.h header defining the checkpoint_list class:
#ifndef __CHECKPOINT_H__
#define __CHECKPOINT_H__
#include "turing_machine.h"
...
#endif
So I want to send to a function from turing_machine.h a list of structures checkpoint but I can't modify anything because that's how the classes must stay.
I have also turing_machine.c:
#include "turing_machine.h"
#include "checkpoint.h"
#include "symbol_table.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
checkpoint_list *c;
So at the beginning I created in turing_machine that list, c, but now I must create it outside and I have to initialize that list c but I don't know how. I hope this is more clear.
I used the term class wrong; I have just .c and .h files.
Reading between the lines, somewhat, I think your trouble is that you have 'mutually referencing' structures.
The way to work around this is with an incomplete type definition:
typedef struct checkpoint_list checkpoint_list;
You can then use that inside turing_machine.h:
#ifndef TURING_MACHINE_H_INCLUDED
#define TURING_MACHINE_H_INCLUDED
#include "tape.h"
#include "alphabet.h"
#include "symbol_table.h"
typedef struct checkpoint_list checkpoint_list;
typedef struct turing_machine
{
...
} turing_machine;
extern checkpoint_list *tm_function(turing_machine *);
extern turing_machine *tm_create(const char *);
#endif
And, inside checkpoint.h, you can write:
#ifndef CHECKPOINT_H_INCLUDED
#define CHECKPOINT_H_INCLUDED
#include "turing_machine.h"
/* No typedef here in checkpoint.h */
struct checkpoint_list
{
...
};
extern checkpoint_list *cp_function(const char *);
extern turing_machine *cp_machine(checkpoint_list *);
#endif
This technique is recognized and defined by the C standard (C90, let alone C99 or C11).
Note that I've also renamed the include guards; names that start with double underscore are reserved for 'the implementation' (meaning the C compiler and its libraries), and you should not invent and use such names in your own code.
Related
I'm trying to write a webserver in C, and I have a header file called route.h. Inside route.h I have the line typedef void (*RouteHandler)(struct HTTPRequest *, struct HTTPResponse *); which I believe creates the typedef RouteHandler which is a function that returns nothing, and takes two pointers to structs as arguments. Also inside route.h is this struct:
struct RouteTableEntry {
enum HTTPMethod method;
char *route;
RouteHandler handler;
};
This code compiles just fine, however when I try and use the typedef in a different header, server.h, I get the compiler error: server.h:27:8: error: unknown type name ‘RouteHandler’.
Here is my code:
route.h
#ifndef ROUTE_H_GUARD_
#define ROUTE_H_GUARD_
#include <stdlib.h>
#include "http.h"
#include "server.h"
typedef void (*RouteHandler)(struct HTTPRequest *, struct HTTPResponse *);
struct RouteTableEntry {
enum HTTPMethod method;
char *route;
RouteHandler handler;
};
...
#endif
server.h
#ifndef SERVER_H_GUARD_
#define SERVER_H_GUARD_
#include <stdint.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include "http.h"
#include "route.h"
...
extern RouteHandler get_handler(enum HTTPMethod method, char *route, RouteHandler handler);
...
#endif
(I've reduced the code to just the relevant parts - if the full thing is necessary I will post the rest)
Your route.h itself includes server.h, and this before the beginning of the scope of the typedef. It is while processing that inclusion of server.h that the compiler complains, rightly, that there is no declaration of type RouteHandler in scope.
If indeed route.h and server.h each require something that the other declares then it is time to refactor. You haven't provided enough details for us to offer specific suggestions, but the kind of circular dependency you presently have will cause you continuing grief.
On the other hand, if route.h actually doesn't need anything from server.h then it ought not to be including it.
I have declared a function in file_utils.h and defined it in file_utils.c At compile time it is gives a conflicting type error.
File_utils.h
#ifndef FILE_UTILS_H
#define FILE_UTILS_H
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) ((dirent)->d_namlen)
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
#endif
bool is_relative_path(struct dirent *ent);
File_utils.c
#include "file_utils.h"
#include <stdbool.h>
#include <dirent.h>
bool is_relative_path(struct dirent *ent){
return (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0);
}
Error:
abhiram#abhiram-Lenovo-G50-70:~/libpostal-master/src$ gcc -DLIBPOSTAL_DATA_DIR='"$//home/abhiram/libpostal-master/data"' -o main main.c libpostal.c file_utils.c json_encode.c string_utils.c -std=c99 -w
file_utils.c:45:6: error: conflicting types for ‘is_relative_path’
bool is_relative_path(struct dirent *ent){
^
In file included from file_utils.c:1:0:
file_utils.h:59:6: note: previous declaration of ‘is_relative_path’ was here
bool is_relative_path(struct dirent *ent);
^
I have included both dirent.h and stdbool.h libraries.
Resolve all compiler warnings.
Compile with all compiler warnings enabled -Wall -Wextra.
Resolve all compiler warnings.
The code you posted has a missing #endif, maybe probably from #ifdef HAVE_DIRENT_H, but I am guessing the last line of the file_utils.h should be a closing #endif.
The warning I get from gcc is this:
warning: ‘struct direct’ declared inside parameter list
warning: its scope is only this definition or declaration, which is probably not what you want
This is the the most important warning.
Structure definition is only valid inside function parameter list. Ex:
void other_f(
struct B a // this will forward declare struct B
// scope of this variable is _only_ inside function parameter list
); // here struct B get's out of scope!
struct B b; // will error, there is no struct B here
// struct B was declared inside function parameter list
// you can't use it anywhere else
The MCVE to your problem would be this example:
void f(struct A);
struct A;
void f(struct A); // error conflicting types for 'f'
The struct A will be declared (I call it "auto-declared") inside the function parameter list void f( <here> ) on the first use. The structure declaration will be visible only inside the parameter list. So it's similar to a pseudocode:
{
struct A; // type only valid inside `{` `}` braces
void f(struct A a); // imagine this symbol is visible outside `{` `}`
}
ie. the struct A is not visible outside the { }.
Then you declare another struct A:
struct A;
void f(struct A a);
But this struct A is different type as the other struct A. As it's different struct A, the function f is different, the compiler issues an error.
No consider your header:
#define dirent direct
...
bool is_relative_path(struct dirent *ent);
I don't know if direct is a typo or not. But you need to forward declare the struct direct, so that the forward declaration of struct direct is visible outside the function parameter list of is_relative_path function.
struct direct;
#define dirent direct
...
// or here:
struct dirent;
bool is_relative_path(struct dirent *ent);
Your problem seems to be file inclusion order if "File_utils.c" and / or a missing definition of HAVE_DIRENT_H.
In the given inclusion order, "file_utils.h" has no idea what a struct dirent is, since (presumably HAVE_DIRENT_H) is defined within <dirent.h>. If this is NOT the case, simply ensure that HAVE_DIRENT_H IS defined before including "file_utils.h"
The net effect as-is in the code is that in "file_utils.h", bool is_relative_path(struct dirent *ent) is actually seen as bool is_relative_path(some_pointer_to_an_unknown_struct_type ent), while the "file_utils.c" sees the function signature as as bool is_relative_path(a_pointer_to_a_struct_type_i_definately_know_about ent).
Thus the two files do NOT agree on the function signature.
Edit
#n.m. is correct in that "file_utils.h" essentially sees a distinct definition of struct dirent, and that one cannot declare a type inside a function parameter list.
TLDR
Edit File_utils.c to define HAVE_DIRENT_H and / or #include <dirent.h> before #include "file_utils.h" so that both "file_utils.h" and "file_utils.c" see a common function signature for bool is_relative_path(struct dirent *ent)
It looks like the declaration of bool is_relative_path(struct dirent *ent); is AFTER the #endif preprocessor declaration (include guards). That mean including this header file in two different files will cause two declarations. Have a look at this: https://en.wikipedia.org/wiki/Include_guard to get some more details
This should fix it:
#ifndef FILE_UTILS_H
#define FILE_UTILS_H
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) ((dirent)->d_namlen)
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
// moved the declaration between the #ifndef #endif block
bool is_relative_path(struct dirent *ent);
#endif
You cannot declare a type inside a function parameter list. This is what happens when in File_utils.h you have a declaration of is_relative_path with no prior declaration of stuct dirent.
Either #include <dirent.h> in File_utils.h (recommended), or add a declaration
struct dirent;
somewhere in it above is_relative_path.
A toy code illustrating my problem is as follows:
stuff.h:
#ifndef STUFF
#define STUFF
int a;
int testarr[]={1,2,3};
#endif
fcn.h:
#include "stuff.h"
int b[]={5,6,7};
void fcn();
main.h:
#include "stuff.h"
#include <stdio.h>
fcn.c:
#include "main.h"
void fcn() {
printf("Hello\n");
}
main.c:
#include "main.h"
#include "fcn.h"
int main() {
fcn();
printf("HI\n");
}
An attempt to compile fails with:
/g/pe_19976/fcn_2.o:(.data+0x40): multiple definition of `testarr'
/g/pe_19976/main_1.o:(.data+0x40): first defined here
After doing some reading, I realize that defining the array testarr in the header file is a problem. But the thing is, in my real code, several files need access to testarr and it needs to have the same assigned values everywhere. I guess I could put it in main.h (?) but even if that would work, in my real code it logically belongs in stuff.h. How do I solve this conundrum?
BTW, based on something else I found, I tried defining testarr as extern but got the same problem.
When you put a variable definition into a header file, any .c file that includes it will have a copy of that variable. When you then attempt to link them, you get a multiple definition error.
Your header files should contain only a declaration of the variable. This is done using the extern keyword, and with no initializer.
Then in exactly one .c file, you put the definition along with an optional initializer.
For example:
main.c:
#include "main.h"
#include "fcn.h"
int a;
int testarr[]={1,2,3};
int main() {
fcn();
printf("HI\n");
}
stuff.h:
#ifndef STUFF
#define STUFF
extern int a;
extern int testarr[];
#endif
fcn.h:
#include "stuff.h"
extern int b[];
void fcn();
fcn.c:
#include "main.h"
int b[]={5,6,7};
void fcn() {
printf("Hello\n");
}
It is not clear why you are using so many global variables. The array
int testarr[]={1,2,3};
is defined as many times as there are compilation units (in your example there are at least two compilation units) that include the corresponding header.
Declare the array in a header like
extern int testarr[3];
and define it in a cpp module.
int testarr[]={1,2,3};
The same is valid for other global variables that have external linkage.
As for this remark
BTW, based on something else I found, I tried defining testarr as
extern but got the same problem.
Then the array with the specifier extern shall not be initialized in a header. Otherwise it is a definition of the array.
I am building a project that I am trying to organize as follows:
main.c
globals.h
structures.h
FunctionSet1.c, FunctionSet1.h
FunctionSet2.c, FunctionSet2.h
etc.
I thought I could define a structure type in structures.h:
struct type_struct1 {int a,b;}; // define type 'struct type_struct1'
then declare a function1() returning a structure of type type_struct1 in FunctionSet1.h:
#include "structures.h"
struct type_struct1 function1(); // declare function1() that returns a type 'struct type_struct1'
then write function1() in FunctionSet1.c:
#include "FunctionSet1.h"
struct type_struct1 function1() {
struct type_struct1 struct1; // declare struct1 as type 'struct type_struct1'
struct1.a=1;
struct1.b=2;
return struct1;
}
Edit: with the corrected code above, the compiler returns
306 'struct' tag redefined 'type_struct1' structures.h
Is the file set good practice ?
What is the good practice to manage the structures ?
In your example, you declare a structure named type_struct in structure.h, then in FunctionSet1.h the structure that you are returning is type_struct, and in the .c it is called struct1.
So i think that the problem is that struct1 and type_struct are not recognized because they have never been defined ...
However, the organization of your files is fine.
Your general structure looks good. One thing you need to do, as zenith mentioned, is to put include guards into your header files. What that is is a set of #define's that make sure that the contents of the header are not included more that once in a given file. For example:
structures.h:
#ifndef STRUCTURES_H
#define STRUCTURES_H
struct type_struct1{
int a,b;
};
...
// more structs
...
#endif
FunctionSet1.h:
#ifndef FUNCTION_SET_1_H
#define FUNCTION_SET_1_H
#include "structures.h"
struct type_struct1 function1();
...
// more functions in FucntionSet1.c
...
#endif
main.c:
#inlcude <stdio.h>
#include "structures.h"
#include "FunctionSet1.h"
int main(void)
{
struct type_struct1 struct1;
struct1 = function1();
return 0;
}
Here, main.c includes structures.h and FunctionSet1.h, but FunctionSet1.h also includes structures.h. Without the include guards, the contents of structures.h would appear twice in the resulting file after the preprocesser is done. This is probably why you're getting the "tag redefined" error.
The include guards prevent these type of errors from happening. Then you don't have to worry about whether or not a particular header file was included or not. This is particularly important if you're writing a library, where other users may not know the relationship between your header files.
First of all, you have to declare the structure in your file.h (you can use typedef to create an alias)
typedef struct Books
{
char title[50];
int book_id;
} books;
then, you have to include your file.h in your file.c and declare your variable like this
#include "file.h"
int main()
{
books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
or like this if you didn't use typedef
#include "file.h"
int main()
{
struct Books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
Thank you all.
I read again what you said and found that the code above is now correct.
The error I report is with testing the following main.c
#include "structures.h"
#include "FunctionSet1.h"
void main() {
struct type_struct1 struct2;
struct2=function1();
}
in which structures.h is included again, thus causing the error. Removing the include eliminates the error.
I will now look into header guards to avoid such problems.
Thanks again.
well i'm having difficulties, i cant work with struct pointers in other .c files,
always when i'm passing pointers to structs to functions not in the same .c file as the struct it annoying me with such messages. and also when i can't access struct members of one struct from other .c file i'm g
what am i doing wrong? my includes? that's for example two of my structs .h files:
Server.h :
#ifndef SERVER_H
#define SERVER_H
typedef struct Server_s* Server;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Company.h"
#include "Client.h"
#include "Order.h"
#include "SMSServer.h"
#include "MMSServer.h"
Server InstallServer(CompanyL pcompanyList , ClientL pclientList , OrderL porderList);
void RunServer(Server pmainServer);
void OrdersToDoPerTimestamp(FILE *result , Server pmainServer , int currentTimestamp);
#endif
Client.h :
#ifndef _CLIENT_H
#define _CLIENT_H
typedef struct Client_s* Client;
typedef struct ClientNODE* ClientL;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Server.h"
ClientL InstallClients(CompanyL pcompanyList , char* pfileName);
void AppendClientNode(ClientL pclientList , CompanyL pcompanyList , char* ptelNumber , char* pclientType , char* pclientCredit);
Client FindClient(ClientL pclientList, char* pclientTelNumber);
double getCostAndChargeSMSMessage(Client sourceNumber , Company sourceNumberCompany);
#endif
i can create one struck type in other .c files, but later can't access their members?
please guide me a bit.
If you want to give access struct members to other files, you have to put the full struct definition into the header file. E.g:
#ifndef SERVER_H
#define SERVER_H
struct Server_s {
int id;
};
typedef struct Server_s* Server;
#endif
The definition-less idiom you are currently using is meant to hide the implementation details from outside users: others can pass and receive pointers to the structures, but only the defining file (Server.c) can use the struct members.
You can only access struct members if the definition is available, so you'd have to define it in a header if you want to access them from multiple c files.