How to manage global structs in c [duplicate] - c

This question already has answers here:
What exactly do C include guards do?
(3 answers)
Closed 4 years ago.
Honestly I'm not used to working in c and maybe I'm wrong as I approach the problem.
I have 3 files and I need to pass data from one to another
//main.c
#include <stdio.h>
#include "process.h"
#include "readFile.h"
int main() {
int numIn=2, numOut=1;
struct data *allData=readData(numIn, numOut);
process(allData, numIn, numOut);
return 0;
}
// readFile.h
#include <stdio.h>
#include <stdlib.h>
struct data {
double *in;
double *out;
};
struct data * readData(int numIn, int numOut) {
//here I initialize and fill an "allData" array of struct data
return allData;
}
//process.h
#include <stdio.h>
#include <stdlib.h>
#include "readFile.h"
int process(struct data * allData, int numIn, int numOut) {
return 0;
}
If I delete "process.h" and try to print "allData" in the main, the correct data are printed without errors, but when I try to process the data in "process.h" I get this compilation error:
In file included from C:\...\main.c:4:0:
C:\...\readFile.h:11:8: error: redefinition of 'struct data'
struct data
^
In file included from C:\...\process.h:11:0,
from C:\...\main.c:2:
C:\...\readFile.h:11:8: note: originally defined here
struct data
^
In file included from C:\...\main.c:4:0:
C:\...\readFile.h:24:15: error: conflicting types for 'readData'
struct data * readData(int numIn, int numOut)
^
In file included from C:\...\process.h:11:0,
from C:\...\main.c:2:
C:\...\readFile.h:24:15: note: previous definition of 'readData' was here
struct data * readData(int numIn, int numOut)
^

Do not place any code in the .h files
.h files are for the data declarations, extern variables declarations and function declarations.
.c files are correct place to have variable and functions definitions.
Move all the code form the .h files to .c files
Also add the .h file guards. It is just the definition. If this definition is already defined - it means that this file was already included and its content should be skipped
#ifdef MYGUARD_H
#define MYGUARD_H
/* .h file content
#endif

Related

C header files without #ifndef still work...why? [duplicate]

This question already has answers here:
Why are typedef identifiers allowed to be declared multiple times?
(3 answers)
Closed 5 years ago.
Why don't I get the error messages?
I have three header files named DataType.h, printInt.h, printStr.h, and one myApp.c.
DataType.h
typedef int Integer;
typedef char String;
printInt.h
#include "DataType.h"
void printInt(Integer);
printInt.c
#include "printInt.h"
#include <stdio.h>
void printInt(Integer number){
printf("%d\n", number);
}
printStr.h
#include "DataType.h"
void printStr(String*);
printStr.c
#include "printStr.h"
#include <stdio.h>
void printStr(String *str){
printf("%s\n", str);
}
myApp.c
#include "printStr.h"
#include "printInt.h"
Integer main(void){
printInt(20);
printStr("hello");
return 0;
}
Clearly, I have included the DataType.h twice, and I did not use #ifndef to avoid redefinition of Integer and String. Please, someone, tell me how I can get the error messages to demonstrate the directive is working properly.
#ifndef __DATATYPE_H
#define __DATATYPE_H
typedef int Integer;
typedef char String;
#endif
Regardless having #ifndef or not, the gcc complier (version 5.4.0) does not generate any error messages. What's wrong?
Definitions of typedef and prototypes of functions can occur as many times as you want. For example:
typedef int lala;
typedef int lala;
void somePrototype();
void somePrototype();
int main() {
return 0;
}
will compile just fine: https://ideone.com/4EjfaR
Try adding the definition of a function to a header file. You will see then that you get a redefinition error and will require a header guard.

need a workaround for a "multiple definition" error

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.

Passing struct pointer as a parameter

I'm trying to compile this code in c. First of all i have this struct in a separate source file to use it like a "class" (dir.h)
//Structure
typedef struct s_dirobject {
int noteid;
char title[20];
int bytes;
char head[20];
bool is_dir;
struct s_dirobject* next;
} dirobject;
//Ops
void add_dirobject(dirobject* myDirobject,int num_dirobject, char title[20], int is_dir, int bytes, char head[20]);
int get_dirobject_noteid(dirobject* myDirobject,int num_note);
char* get_dirobject_title(dirobject* myDirobject,int num_note);
int get_dirobject_bytes(dirobject* myDirobject,int num_note);
char* get_dirobject_head(dirobject* myDirobject,int num_note);
bool isdir(dirobject* myDirobject, int num_note);
int get_dirobjects_len(dirobject* myDirobject);
void clear_dir(dirobject* myDirobject);
void init_dir(dirobject* myDirobject);
In second place i have the comms source to retrieve the contents of a directory from a remote file system, and fill the object (comms.c)
#include "notebook.h"
#include "dir.h"
dirobject* temporaldirobjects;
...
init_dir(temporaldirobjects);
while(cond) {
//Add retrieved item to the directory
add_dirobject(temporaldirobjects, index, title, is_dir, bytes, "");
}
//When done retrieving the contents from the source i do instantiate the notebook_window
notebook_init(source, path, temporaldirobjects);
Finally, my notebook window interface will look like this. (notebook.h)
#include "dir.h"
void notebook_init(char* source, char* path, dirobject* contents);
void notebook_deinit();
And its implementation (notebook.c)
void notebook_init(char* source, char* path, dirobject* contents) {
// Fill the vars
this_window_source=source;
this_window_path=path;
this_window_dirobjects=contents;
...
}
When i compile this code as is, i get the error saying that
../src/dir.h:13:16: error: redefinition of 'struct s_dirobject'
In file included from ../src/notebook.h:12:0,
from ../src/comms.c:25:
../src/dir.h:13:16: note: originally defined here
In file included from ../src/comms.c:27:0:
../src/dir.h:20:3: error: conflicting types for 'dirobject'
In file included from ../src/notebook.h:12:0,
from ../src/comms.c:25:
../src/dir.h:20:3: note: previous declaration of 'dirobject' was here
In file included from ../src/comms.c:27:0:
../src/dir.h:23:6: error: conflicting types for 'add_dirobject'
In file included from ../src/notebook.h:12:0,
from ../src/comms.c:25:
../src/dir.h:23:6: note: previous declaration of 'add_dirobject' was here
...
since the comms library includes dir.h and notebook.h, and notebook.h does it too.
and if i remove the include in notebook.h i got this other error:
In file included from ../src/comms.c:25:0:
../src/notebook.h:14:46: error: unknown type name 'dirobject'
How can i acheive this? I would like to keep it as clean code as i can.
You included two headers in file comms.c
#include "notebook.h"
#include "dir.h"
header notebook.h in turn includes header dir.h
#include "dir.h"
void notebook_init(char* source, char* path, dirobject* contents);
void notebook_deinit();
As result the structure is defined twice in the same compilation unit. You have to provide that each headers would be included only once in each compilation unit. To do this you have to supply header's quards. For example
#ifndef DIR_H
#define DIR_H
//Structure
typedef struct s_dirobject {
int noteid;
char title[20];
int bytes;
char head[20];
bool is_dir;
struct s_dirobject* next;
} dirobject;
//...
#endif
Or if the compiler supports #pragme once then you could use it.
Usually, multiple declarations are fine in c but multiple definition is not. In your code, you are including dir.h multiple times which is causing the redefinition of struct s_dirobject. Read something about "Header guard" or "Include Guard". here. Hope this solves your major issues with redefinitions.

Multiple Definition of a function in C, Prototyping

Eclipse tells me that I have mutliple Definitions of a function.
I just can't spot the mistake.
This is my main.c
#include <stdio.h>
#include "kontaktverzeichnis.h"
int main(){
kontakt_hinzufuegen();
return 0;
}
This is the header:
#ifndef KONTAKTVERZEICHNIS_H_
#define KONTAKTVERZEICHNIS_H_
#include "kontaktfunktionen.c"
int kontakt_hinzufuegen();
#endif /* KONTAKTVERZEICHNIS_H_ */
and this is kontaktfunktionen.c
#include <stdio.h>
kontakt[];
kontakt_hinzufuegen(){
int i = 0;
printf("Bisher sind %i Kontakte angelegt.",kontakt[i]);
kontakt[i++];
}
struct kontaktname{
char* name;
char* vorname;
};
struct kontaktanschrift{
char* strasse;
int hausnummer;
int plz;
char* ort;
char* land;
};
Where is my error?
You're not supposed to #include C files, that's not the proper way to organize your code.
You should compile the C files separately and then link them together, or compile them all at once with a single compiler invocation.
Do not #include anything in your header file. And do a #include "kontaktverzeichnis.h" in the kontaktfunktionen.c file.
As #StoryTeller commented, define your kontakt_hinzufuegen() as int kontakt_hinzufuegen() in the kontaktfunktionen.c file and return an int value from the function kontakt_hinzufuegen as for ex::
#include <stdio.h>
#include "kontaktverzeichnis.h"
// define the type for this array as below
int kontakt[];
int kontakt_hinzufuegen(){
int i = 0;
printf("Bisher sind %i Kontakte angelegt.",kontakt[i]);
kontakt[i++];
// Return an int value
return 0 ;
}
Your error is that in kontaktfunktionen.h you are including kontaktfunktionen.c. This will include all the definitions and declarations from kontaktfunktionen.c which are already declared when you use kontaktfunktionen.c
As others have said: You should not include .c files in your header files.

#including files [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I got a problem with including files.
What I've basically made is a command-line program in C that works with a csv file. It has 5 commands: -menu, -add, -edit, -del, -verify. All is good except for the -menu. What needs to happen when I type "./passweb -menu" is for a visual menu to appear. This menu command should call a new function and it needs to be located in a separate c file (aka menu.c).
The problem I'm having right now is that I'm not too sure how to include the files to run in the menu.c because the way I have it set up right now, passweb.c has all the functions such as -add and -edit and etc. I know you need to make header files and such but it's complaining that I've declared the methods twice which is true since I use the functions in the menu file.
Here's some of the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cipher.h"
#include "menu.h"
#include "passweb.h"
#define MAXLENGTH 51 //longest length of a single record + 1 =51 bytes
#define SIZEOFDB 1000
#define ENCRYPT 5
typedef struct rec
{
char name[MAXLENGTH];
char pw[MAXLENGTH];
char type[6];
int boolean;
}RECORD;
int add(char *nName, char *nPw, char *nType, RECORD *arr, int size);
void del (char *tName, RECORD *arr, int size);
int edit(char *nName, char *nPw, char *nType, char *tName, char *tPw, RECORD *arr, int size);
int verify (char *tName, char *tPw, RECORD *arr,int size);
This is my main file "passweb.c" and it's declared the functions.
Later on in the main, I will call a menu function which is located in a menu.c file.
In the menu function I use "add","edit","del" and etc that I wrote in this .c file.
As you can see on the top, I have included the header files.
What can I do to solve this problem?
Sorry for the long post.
Thanks
You should put function prototype in the header file. You should put its implementation in the source file, which should include the header file.
For example, the header (test.h) would have the structure definitions and function prototypes like:
#ifndef TEST_H
#define TEST_H
struct myStruct {
int x;
};
int Add(int lhs, int rhs);
#endif
And the source would have:
#include "test.h"
#include <stdio.h>
int Add(int lhs, int rhs)
{
return lhs+rhs;
}
int main()
{
printf("%d",Add(2,3));
return 0;
}
put this in your header file and include it:
#ifndef FUNCS_H_
#define FUNCS_H_
int add(char *nName, char *nPw, char *nType, RECORD *arr, int size);
void del (char *tName, RECORD *arr, int size);
int edit(char *nName, char *nPw, char *nType, char *tName, char *tPw, RECORD *arr, int size);
int verify (char *tName, char *tPw, RECORD *arr,int size);
#endif /*FUNCS_H_*/
the #ifdef guards the header from multiple inclusion
Move the declaration of add, del, edit and verify in a new include file main.h
Include main.h in your main .c file and in menu.c
In general is also a good idea to put directives in the include files that tells the preprocessor to use them only once - Visual C++ has a special #pragma once directive for that, otherwise you can use
#if ! __MENU_C
#define __MENU_C
. . . .
#endif
The header file should contain your function prototypes and the necessary information about the data types they reference, such as your struct definitions. It may also include #define'ed constants, inline functions, declarations of extern variables (which would be declared normally inside one of your .c files), etc.
Once you have these things in your header file, you can remove them from the .c file(s); the actual function definitions, with the bodies, should be in the .c files -- but don't duplicate the prototypes there. You then #include the header in each .c file that needs the functions, etc. declared in it.
You also need to ensure that the items in the header file don't get #include'ed more than once in each source file, even indirectly (included from another include). Usually header guards are used for this, which use preprocessor conditionals to prevent processing of the header file when it has already been included:
#ifndef SOMEHEADER_H
# define SOMEHEADER_H
/* header file contents */
#endif
When compiling, you should be able to compile each .c file separately if you like, or all together if the compiler lets you. When linking, you need to link all the object files though. For gcc, doing both in one command, you might use something like this:
gcc -o program_name first.c second.c third.c
...which compiles each .c file to its own .o file, and links all of them together when producing the executable.

Resources