I am just starting to learn C so hopefully this isn't a dumb question. The problem I am having is regarding header files and using #define for constants. I have read that I should use the following to prevent my header from being compiled more than once.
#ifndef NAME_OF_FILE
#define NAME_OF_FILE
.
. //my header file content
.
#endif
I want to add a constant, and I believe I would also use a #define such as,
#ifndef NAME_OF_FILE
#define NAME_OF_FILE
#define NUM_CONST 5 //the constant I want in my header file
.
.
.
#endif
How does C know that #define NAME_OF_FILE is referring to the .h file while #define NUM_CONST 5 is just a constant? Is it because of the value at the end of NUM_CONST? Or do I have this all completely wrong?
There is no essential difference between the two defines. #define NAME_OF_FILE and #define NUM_CONST 5 are the same sort of thing. They define a plaintext replacement of tokens (in the first case, the replacement is nothing).
For example you could put subsequent code:
printf("%d\n", NAME_OF_FILE NUM_CONST NAME_OF_FILE);
and after the above substitutions the code would turn in to:
printf("%d\n", 5);
which is correct. There is no "magic". The compilation step that performs these substitutions is usually known as "preprocessing".
NAME_OF_FILE does not refer to the .h file, per se, but the use of the ifndef directive achieves the goal of not compiling the same code twice.
It doesn't. NAME_OF_FILE could be anything. You could have
#ifndef PRETTY_PINK_PRINCESS
#define PRETTY_PINK_PRINCESS
/* definitions */
#endif
And it would work just as well. Using NAME_OF_FILE is just a convention because it makes it likely that it's unique.
#define IDENTIFIER defines the identifier for the sakes of #ifdef, but what it is being defined to is the empty string.
So,
#define NAME_OF_FILE
int main()
{
int x = NAME_OF_FILE;
}
would resolve to
int main()
{
int x = ;
}
So there is no "knowing" involved, just a defined-but-empty.
(That is why some style guides out there recommend #define NAME_OF_FILE NAME_OF_FILE, so that if NAME_OF_FILE happens to be used in the source, it is replaced-with-self by the preprocessor.)
For the compiler both these statement are the same type a macro
#define NAME_OF_FILE
#define NUM_CONST 5
That this construct
#ifndef NAME_OF_FILE
#define NAME_OF_FILE
.
. //my header file content
.
#endif
is doing, is that the header is processed for the first time, the marco "NAME_OF_FILE" is n ot defined, hence it get defined and the whole header file content processed. The second time the compiler comes around this, because the header was included in project more than once, is that the marco is defined now and the header file doesn't get processed again.
Again, the "c-code" is not aware, that the marco __TEST_H for example has its because the header file's name is 'test.h'. What you are reffering to is probably, that your IDE auto-generated the marco then you created the header file and that the IDE called the marco after the file for the user's convenience. Like a another one here allready said, that you can rename the marco (rename it in the whole project I mean by that) and the code would compile and generally behave exactly like before.
Related
I have a macro that should be used both in my source file and header one. However I don't wan't other code linked to the final object to access that macro (more than anything else I don't want the macro to go causing unexpected errors in other files). I thought about using a macro with a long and complicated name that will be unlikely used from other code, however this solution kinda looks ugly to me. Obviously the most simple solution would be to undefine the macro in some way, however if I define the macro in the header and then undefine it – I think – I won't be able to access it anymore from the source file. What should I do?
// hi.h
#define string char *
void greet(string x);
// hi.c
#include "hi.h"
void greet(string x) {
printf("Hi!");
}
Okay, don't kill me, this was just an example, i know #define string char * is horrible.
Last minute thought: Maybe I can underfine the macro at the end of the source file, is this acceptable to do?
I guess you could conditionally "undefine" macro at the end of the header when the a magic macro is not defined. The blessed source file would have to define this macro prior to including a header.
// header.h
...
#ifndef MAGIC_MACRO
#undef string
#endif
// common source
#include "header.h"
// blessed source
#define MAGIC_MACRO
#include "header.h"
This solution will work great as long as no macro defined inside the header uses string macro.
What should I do?
Pick option 1 a macro with a long and complicated name that will be unlikely used from other code as it's the simplest and most obvious. Do not use a complicated name - just use a name so that you and other developers will know it's a private symbol, that's all.
// hi.h
// this macro is private
#define _lib_string char *
Remember about reserved words. Example: https://github.com/GNOME/glib/blob/main/glib/glib-private.h#L32 .
he most simple solution would be to undefine the macro in some way, however if I define the macro in the header and then undefine it – I think – I won't be able to access it anymore from the source file
If you go this way, you'll end up with spaghetti code, where some global state affects what you have. For example:
// hi.h
#define string char *
void greet(string x);
#ifndef FROM_HI_C
#undef string
#endif
// hi.c
#define FROM_HI_C
#include "hi.h"
void greet(string x) {
printf("Hi!");
}
Maybe I can underfine the macro at the end of the source file, is this acceptable to do?
Other files see only the header file - they are unaffected by anything in the source file.
All across our C code base, I see every macro defined the following way:
#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS 0.2f
#endif
#ifndef BEEPTRIM_ROLL_RATE_DEGPS
#define BEEPTRIM_ROLL_RATE_DEGPS 0.2f
#endif
#ifndef FORCETRIMRELEASE_HOLD_TIME_MS
#define FORCETRIMRELEASE_HOLD_TIME_MS 1000.0f
#endif
#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS 50.0f
#endif
What is the rationale of doing these define checks instead of just defining the macros?
#define BEEPTRIM_PITCH_RATE_DEGPS 0.2f
#define BEEPTRIM_ROLL_RATE_DEGPS 0.2f
#define FORCETRIMRELEASE_HOLD_TIME_MS 1000.0f
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS 50.0f
I can't find this practice explained anywhere on the web.
This allows you to override the macros when you're compiling:
gcc -DMACRONAME=value
The definitions in the header file are used as defaults.
As I said in the comment, imagine this situation:
foo.h
#define FOO 4
defs.h
#ifndef FOO
#define FOO 6
#endif
#ifndef BAR
#define BAR 4
#endif
bar.c
#include "foo.h"
#include "defs.h"
#include <stdio.h>
int main(void)
{
printf("%d%d", FOO, BAR);
return 0;
}
Will print 44.
However, if the conditional ifndef was not there, the result would be compilation warnings of MACRO redefinition and it will print 64.
$ gcc -o bar bar.c
In file included from bar.c:2:0:
defs.h:1:0: warning: "FOO" redefined [enabled by default]
#define FOO 6
^
In file included from bar.c:1:0:
foo.h:1:0: note: this is the location of the previous definition
#define FOO 4
^
I do not know the context but this can be used to give the user the availability to override the values set by those macro definitions. If the user explicitly defines a different value for any of those macros it will be used instead of the values used here.
For instance in g++ you can use the -D flag during compilation to pass a value to a macro.
This is done so that the user of the header file can override the definitions from his/her code or from compiler's -D flag.
Any C project resides on multiple source files. When working on a single source file the checks seem to (and actually) have no point, but when working on a large C project, it's a good practice to check for existing defines before defining a constant. The idea is simple: you need the constant in that specific source file, but it may have been already defined in another.
You could think about a framework/library that gives to the user a default preset that allow the user to compile and work on it.
Those defines are spreaded in different files and the final user is advised to include it's config.h file where he can config its values.
If the user forgot some define the system can continue to work because of the preset.
Using
#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS 0.2f
#endif
allows the user to define the value of the macro using the command line argument (in gcc/clang/VS) -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.
There is another important reason. It is an error to re-define a preprocessor macro differently. See this answer to another SO question. Without the #ifndef check, the compiler should produce an error if -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f is used as a command line argument in the compiler invocation.
On Apple's opensource website, the entry for stdarg.h contains the following:
#ifndef _STDARG_H
#ifndef _ANSI_STDARG_H_
#ifndef __need___va_list
#define _STDARG_H
#define _ANSI_STDARG_H_
#endif /* not __need___va_list */
#undef __need___va_list
What do the #define statements do if there's nothing following their first argument?
There are sort of three possible "values" for an identifier in the preprocessor:
Undefined: we don't know about this name.
Defined, but empty: we know about this name, but it has no value.
Defined, with value: we know about this name, and it has a value.
The second, defined but empty, is often used for conditional compilation, where the test is simply for the definedness, but not the value, of an identifier:
#ifdef __cplusplus
// here we know we are C++, and we do not care about which version
#endif
#if __cplusplus >= 199711L
// here we know we have a specific version or later
#endif
#ifndef __cplusplus // or #if !defined(__cplusplus)
// here we know we are not C++
#endif
That's an example with a name that if it is defined will have a value. But there are others, like NDEBUG, which are usually defined with no value at all (-DNDEBUG on the compiler command line, usually).
They define a macro which expands to nothing. It's not very useful if you intended it to be used as a macro, but it's very useful when combined with #ifdef and friends—you can, for example, use it to create an include guard, so when you #include a file multiple times, the guarded contents are included only once.
You define something like:
#define _ANSI_STDARG_H_
so that, later you can check for:
#ifdef _ANSI_STDARG_H_
I have the following curiosity about the include files and how they are managed (with GCC):
Let's say I have one source file foo.c and three headers foo.h, foo_cfg.h and foo_int.h.
In foo.c:
#include "foo.h"
#include "foo_int.h"
In foo.h:
#include "foo_cfg.h"
In foo_cfg.h:
/* no inclusions */
#define FOO BAR
In foo_int.h:
/* no inclusions */
#define BAR 0U
I am wondering why the compilation succeeds. Shouldn't the foo_cfg.h file complain that it doesn't know about BAR symbol?
Furthermore I have another source file bar.c which only includes the foo.h file and still works.
Remark: this is from a project I am working on with a complex build environment of which I don't have to much details. Could it be that the build environment has an effect on this other than specifying the location for the header files?
It might be that the question is really stupid or I've overlooked something and I apologize if so.
No, it's ok.
You see, the preprocessor doesn't care if BAR is defined or not at all. It just replaces the string FOO with BAR in the source code which follows, without actually caring if it's defined at that point or not.
Next, at the actual .c file (the thing where the compilation starts) both headers are included, so the compiler sees both substitutions: FOO -> BAR and BAR -> 0U. So it successfully applies both of them.
The headers are never compiled alone, they are always compiled as a part of .c file which #includes that header. (The preprocessor just pretends that the content of the header is pasted to the place where #include is located.) So, for the preprocessor your file foo.c looks like this:
/* no inclusions */
#define FOO BAR
/* no inclusions */
#define BAR 0U
/* the rest of the file... */
/* for example: */
unsigned int i = FOO;
And the compiler after the preprocessing sees just this:
/* no inclusions */
/* no inclusions */
/* the rest of the file... */
/* for example: */
unsigned int i = 0U;
(not quite sure, maybe the preprocessor removes the comments as well.)
Edit:
Indeed, as #pmg mentions, the preprocessor replaces comments with a whitespace, so the real preprocessed text which is fed to the compiler is just
_
_
_
_
unsigned int i = 0U;
(here _ denotes a whitespace)
To extend Vlad's answer a bit:
Preprocessor macros are expanded when used, not when defined.
So when you write #define FOO BAR, all it does is remember that FOO=BAR.
When you write #define BAR 0U, it remembers that BAR=0U.
Now, when FOO is seen in the code, it's replaced with BAR, which is immediately replaced with 0U.
The order in which #define FOO and #define BAR appear in the source is unimportant. The important thing is that when FOO is seen the first time, both definitions were already done.
If I have a constant defined as such in a header file:
#define MY_CONSTANT 1
And I include a library to the whole project which includes a different definition for the same constant:
#define MY_CONSTANT 0
I naturally get conflicts while compiling. Supposing that I cannot alter my project code and that I can only change my library code, what can I do to make MY_CONSTANT as defined by my lib?
EDIT:
just to clarify, my goal is to update a constant in my code through a library. Because I'm writing a library to simulate hardware functions, I have to go by the rule that the software itself must be untouched. There is a loop of sort in the main file that uses the constant. I need to change this constant, but without actually altering it in the main file.
You can undefine the other definition
#ifdef MY_CONSTANT
#undef MY_CONSTANT
#endif
#define MYCONSTANT 0
Also, you should remove the =, and the ;
P.S. as mentioned, it will not change the code that already compiled.
You can #undef MY_CONSTANT and redefine to the value you want, but that's just asking for trouble. See if you can modify the design entirely so that MY_CONSTANTs don't clash.
Undef, redef, and then redef it back
#ifdef MY_CONSTANT
#undef MY_CONSTANT
#endif
#define MY_CONSTANT 0
/* code here */
#undef MY_CONSTANT /* not needed if you don't need the library's definition*/
#include "library.h" /* file that originally defined it
might not work if include guards prevent it
in that case #undef LIBRARY_H
although that causes more trouble :( */