If I have 3 files:
header1.h
header2.h
header3.h
And I did #include "header1.h" in header2.h, then if I do #include "header2.h" in header3.h does header3.h have header1.h's declarations?
Yes, provided that there are no conditional compiling statements that may prevent such inclusions from happening.
For example, in this situation, header1.h won't be included from header3:
header2:
...
#ifndef THING
#include "header1.h"
#endif
...
header3:
...
#define THING
#include "header2.h"
...
Related
I have two source files, main.c and datamgr.c - and two header files, config.h and datamgr.h
The testing system we're using expects these files, and only these files.
main.c:
#include "datamgr.h"
#include "config.h"
int main() {
custom_type a = 1;
a = foo();
return 0;
}
datamgr.c:
#include "datamgr.h"
#include "config.h"
custom_type foo() {
custom_type a = 1;
return a;
}
datamgr.h:
#ifndef DATAMGR_H
#define DATAMGR_H
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
custom_type foo();
#endif
config.h:
#ifndef CONFIG_H
#define CONFIG_H
#ifndef SET_MAX_TEMP
#error "Max temperature not set."
#endif
#ifndef SET_MIN_TEMP
#error "Max temperature not set."
#endif
typedef custom_type uint16_t
#endif
Now, the problem is that I can only define SET_MAX_TEMP and SET_MIN_TEMP in main.c, but both main.c and datamgr.c need both the header files. So if I leave them undefined in datamgr.c I get a compiler error. However, if I do define them in datamgr.c and later overwrite them in main.c, I get a different compiler error.
Please, any assistance as to how to get this horrible setup to work would be greatly appreciated.
You can pass these defines directly while compiling:
gcc -DSET_MAX_TEMP -DSET_MIN_TEMP <your files>
In datamgr.c do:
#define SET_MAX_TEMP
#define SET_MIN_TEMP
#include "datamgr.h"
#include "config.h"
#undef SET_MAX_TEMP
#undef SET_MIN_TEMP
In a comment, you said:
Because main.c is the file that our testing system uses to implement the test scenarios.
In that case, make sure that the testing system defines those macros in the command line of the compiler for every file being compiled.
I have code that I can't compile on one computer. It works on my PC, but on another it doesn't work. The error is "redefinition of typdef cplx" even though I have guard on every header file and I have guard for every definition of typdef:
#ifdef __cplusplus
#include <complex>
#include <cmath>
typedef std::complex<double> cplx;
#else
#include <tgmath.h>
typedef double complex cplx;
#endif
Why this problems occurs?
Here are two header files. blas.h:
#ifndef BLAS_H
#define BLAS_H
#ifdef __cplusplus
#include <complex>
#include <cmath>
typedef std::complex<double> cplx;
#else
#include <tgmath.h>
typedef double complex cplx;
#endif
//declaration of functions
#endif
and lapack.h:
#ifndef LAPACK_H
#define LAPACK_H
#ifdef __cplusplus
#include <complex>
#include <cmath>
typedef std::complex<double> cplx;
#else
#include <tgmath.h>
typedef double complex cplx;
#endif
//declarations of functions
#endif
The problem is when I include both, lapack.h and blas.h, I get this error?
Your guards protect against the same include file being included twice, but you have two different include files with two different guards, and you define cplx in each one.
You need a separate guard for that type in each include file, like this:
#ifndef CPLX
#define CPLX
#ifdef __cplusplus
#include <complex>
#include <cmath>
typedef std::complex<double> cplx;
#else
#include <tgmath.h>
typedef double complex cplx;
#endif
//declarations of functions
#endif
I have the following code in main.c
#include "config.h"
#include "util.h"
and in config.h
#include "util.h"
and there is a normal function in util.h
as I have include the util.h twice, I expect it should be wrong
but unfortunately, it goes damn well when I type: gcc main.c config.c util.c
why is this right?
it should not cause an error
if you have next files:
inc.h, inc1.h and inc.h includes inc1.h and inc1.h includes inc.h, then it cause of error
in the header files made following agreement:
#ifndef HEADER_NAME_H
#defiene HEADER_NAME_H
//body of header file
#endif /*HEADER_NAME_H*/
where HEADER_NAME_H is "header_name.h" filename
C headers usually have header guards that prevent them to be included multiple times. For example:
#include <stdio.h>
#include <stdio.h> // multiple inclusion of stdio.h, that's fine
A header guard is placed at the top of the header:
#ifndef MYHEADER_H
#define MYHEADER_H
// content of the header file
#endif MYHEADER_H
I'm trying to make some project in C.
I would like to know if it is possible to make #include from the same file twice, in a way that recalls diamond heritage.
i.e.
in a.c there is #include "a.h"
in b.c there is #include "b.h"
in b.h there is #include "a.h"
Is it possible to #include "b.h" in a.c?
I get an error:
some_variable already defined in a.obj
Simple: don't define variables in headers, just declare them:
Header:
// a.h
#ifndef A_H // always use #include guards
#define A_H
extern int my_variable; // declare my_variable
...
#endif
Source file a.c:
// a.c
#include "a.h"
int my_variable; // define my_variable
...
Source file b.c:
// a.c
#include "a.h"
#include "b.h"
...
As others have mentioned, #include guards are useful, and a good habit to get into, but they are probably not the solution for this specific problem.
You have to declare extern the variables in a.h, then modify your header a.h in the following way:
#ifndef a_h
#define a_h
//your a.h
#endif
So I'm still getting used to modular programming, and want to make sure I'm adhering to best practices. If I have the two module header files below, will the the headers #included by each file (for example "mpi.h") be included multiple times? Is there a proper way to account for this?
Also, my module headers typically look like these examples, so any other criticism/pointers would be helpful.
/* foo.h */
#ifndef FOO_H
#define FOO_H
#include <stdlib.h>
#include "mpi.h"
void foo();
#endif
and
/* bar.h */
#ifndef BAR_H
#define BAR_H
#include <stdlib.h>
#include "mpi.h"
void bar();
#endif
And use the sample program:
/* ExampleClient.c */
#include <stdlib.h>
#include <stdio.h>
#include "mpi.h"
#include "foo.h"
#include "bar.h"
void main(int argc, char *argv[]) {
foo();
MPI_Func();
bar();
exit(0)
}
What do you mean by 'include'? The preprocessor statement #include file copies the contents of file and replaces the statement with these contents. This happens no matter
If by 'include' you mean "the statements and symbols in these files will be parsed multiple times causing warnings and errors", then no, the include guards will prevent that.
If by 'include' you mean "some part of compiler will read some part of these files", then yes, they'll be included multiple times. The preprocessor will read the second inclusion of the file and replace it with a blank line because of the include guards, which incurs a tiny overhead (the file is already in memory). Modern compilers (GCC, not sure about others) will probably be optimized to avoid this, however, and note that the file has include guards on the first pass and simply discard future inclusions, removing the overhead - Don't worry about speed here, clarity and modularity are more important. Compilation is a time-consuming process, for sure, but #include is the least of your worries.
To better understand include guards, consider the following code sample:
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
// Define to 1 in first block
#define GUARDED 1
#endif
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
// Redefine to 2 in second block
#define GUARDED 2
#endif
After (the first pass of) preprocessing, what will GUARDED be defined to? The preprocessor statement #ifndef or its equivalent, #if !defined() will return false if their argument is indeed defined. Therefore, we can conclude that the second #ifndef will return false, so only the first definition of GUARDED will remain after the first pass of the preprocessor. Any instance of GUARDED remaining in the program will be replaced by 1 on the next pass.
In your example, you've got something slightly (but not much) more complicated. Expanding all the #include statements in ExampleClient.c will result in the following source: (Note: I indented it, but that's not normal style for headers and the preprocessor won't do it. I just wanted to make it more readable)
/* ExampleClient.c */
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include <stdio.h>
#ifndef STDLIB_H
#define STDLIB_H
#define NULL 0 //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
//#include "foo.h"
#ifndef FOO_H
#define FOO_H
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
void foo(void);
#endif
//#include "bar.h"
#ifndef BAR_H
#define BAR_H
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
void bar(void);
#endif
void main(int argc, char *argv[]) {
foo();
MPI_Func();
bar();
exit(0); // Added missing semicolon
}
Go through that code and note when various definitions are performed. The result is:
#define STDLIB_H
int abs (int number); //etc.
#define STDLIB_H
#define NULL 0 //etc.
#define MPI_H
void MPI_Func(void);
#define FOO_H
void foo(void);
#define BAR_H
void bar(void);
With respect to your request for other criticism/pointers, why are you #including stdlib.h and mpi.h in all your headers? I understand that this is a stripped down example, but in general, header files should only include files necessary for the declaration of their contents. If you use a function from stdlib or call MPI_func() in foo.c or bar.c, but the function declarations are simply void foo(void), you shouldn't include these files in the header function. For example, consider the following module:
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c:
#include <stdlib.h> // Defines type size_t
#include "mpi.h" // Declares function MPI_func()
#include "foo.h" // Include self so type definitions and function declarations
// in foo.h are available to all functions in foo.c
void foo(void);
size_t length;
char msg[] = "Message";
MPI_func(msg, length);
}
In this example, the implementation of foo() requires stuff from stdlib and mpi, but the definition does not. If foo() returned or required a size_t value (typedef'ed in stdlib), you'd need to #include stdlib in the .h file.
Mostly no, with a bit 'yes'. Your header files will be 'read' more than once but at second and later time the preprocessor will cut off all the contents. This implies that it won't waste your compiler's time and also #includes inside your #ifdef blocks will be done only once (per header file).
It's a good practice. Myself, I also add the following line before #ifdefs:
#pragma once
When supported by the particular compiler, it guarantees that the file will actually be read only once. I think it's a little bit more optimal that way.
So, to sum up:
header guards like you are using prevent compiler from interpreting the header contents more than once but possibly can cause the preprocessor to parse it more than once (which is not a big problem),
#pragma once causes the particular header file to be read only once.
When using both, #pragma once should be in effect if supported by compiler; if not, header guards will apply.
1) GOOD: you have an "include guard". "stdlib.h", "mpi.h" and "void foo()" are only seen by the compiler the first time you #include "foo.h"
/* foo.h */
#ifndef FOO_H
#define FOO_H
#include <stdlib.h>
#include "mpi.h"
void foo();
#endif
2) BAD: This will #include the entire contents of "foo.h" every time you use it:
/* foo.h */
#include <stdlib.h>
#include "mpi.h"
void foo();
3) By #include", I mean "once per compilation unit" (i.e. the same .c source file).
This mainly "protects" against a header (foo.h) calling another header ("bar.h) which might recursively call the first header.
Every different compilation unit that #includes foo.h will always get "stdlib.h", "mpi.h" and "void foo()". The point is that they'll be seen only once - not multiple times in the same compilation unit.
4) This is all "compile-time". It has nothing to do with libraries (which are "link time").
Yes, mpi.h will be included multiple times (as will stdlib.h); if mpi.h has include guards similar to foo.h and bar.h, then it won't be an issue.