I have several configuration files each one containing the definition of some boolean macro, to be set to 0 or 1. Then, in my code, I check the value of such a macro to decide which part of the code to activate. Now comes the tricky part: I want to be sure that the header containing the definition of my macro has been included.
In the following example, if I forget to include the header file containing FOO definition, the compiler will print "world!", while I would like instead that it generated an error.
//in the configuration header file
#define FOO 1
//in a cpp file
#if FOO //I would like this to generate an error if I forgot to include the header file
#pragma message "Hello"
#else
#pragma message "world!"
#endif
Is it possible to achieve such a behaviour? How?
To clarify, I am not asking how to generate an error if a macro is not defined, but if it is possible to transform the #if FOO line so that, at the same time, it checks the boolean value and generates an error if FOO is not defined.
The point of having this would be that developers would know that their code should contain
SPECIAL_MACRO(FOO)
which, at the same time, check the boolean value of FOO as if it was an #if FOO statement, and prevents them from forgetting the inclusion of the header defining FOO.
Colleagues (hi Hartmut, Kurt) who maintained a large code base which was extensively configured with #defines ran exactly into the same problem. A simple mis-spelling, possibly in a make file, could result in subtle errors which were hard to track down. Their solution: Use function macros! In
#if SOME_COND()
// ...
#endif
the compiler complains if SOME_COND() is not defined, as opposed to a simple SOME_COND which will be replaced by 0 if undefined. I like it because it can be used to transport several values without cluttering the code up with additional #ifdefs.
The accepted answer of using function-macros is good, but if you want to keep normal macros - and still use the value of FOO if defined and generate an error otherwise you could do:
#if FOO / defined(FOO)
#else
#endif
If FOO is not defined it will trigger integer division by zero.
What about using the -Wundef gcc preprocessor option? This will only generate a warning, which can easily be turned to an error with -Werror=undef.
Macro CHECK(x) will:
fail if macro x is undefined,
evaluate to 00 if x is defined to 0
evaluate to 01 if x is defined to 1
$ cat main.cpp
#define CAT(x, y) x##y
#define CHECK(x) CAT(0, x)
// usage
#define COND0 0
#define COND1 1
#if CHECK(COND)
#endif
#if CHECK(COND0)
#pragma message "defined 1"
#else
#pragma message "defined 0"
#endif
#if CHECK(COND1)
#pragma message "defined 1"
#else
#pragma message "defined 0"
#endif
$ g++ main.cpp
main.cpp:9:1: error: user-defined literal in preprocessor expression
9 | #if CHECK(COND)
| ^~~~~
main.cpp:15:17: note: ‘#pragma message: defined 0’
15 | #pragma message "defined 0"
| ^~~~~~~~~~~
main.cpp:19:17: note: ‘#pragma message: defined 1’
19 | #pragma message "defined 1"
| ^~~~~~~~~~~
I think can solve your problem in simple tricky solution. I change your code as below and my code understand that header.h doesn't exist and show error to me.
#if FOO == 1
#pragma message "Hello"
#elif FOO == 2
#pragma message "world!"
#else
throw std::invalid_argument("Header didn't add to project");
#endif
only you need to change your initial value for Foo.
because compiler activate Foo==0 when it doesn't find FOO, you shouldn't use 0 value for your configuration. you should leave zero for header absence situation.instead you must use values greater than zero(1 , 2, 3 , ...).
Foo==0 absence situation.
Foo==1 Configuration 1.
Foo==2 Configuration 2.
.
.
.
Related
Since preprocessor don't report an error when checking value of preprocessor's symbol that isn't actually defined (usually due to the lack of #include "some_header.h"), I use this cumbersome three line construction with "defined":
#if !defined(SOME_SYMBOL)
#error "some symbol isn't defined"
#endif
#if SOME_SYMBOL == 1
// Here is my conditionally compiled code
#endif
And the way with "#ifndef" is the same.
Is there a more elegant way to perform this check?
In your construction you could use an else block to skip the check for defined:
#if SOME_SYMBOL == 1
// Here is my conditionally compiled code
#else
// error
#endif
But in principle the comments are right. #if !defined and the shorthand #ifndef are the two available versions.
Currently, you are checking if SOME_SYMBOL is equals to 1. Do you execute different code based on that value ?
If not, you could simply use:
#ifdef SOME_SYMBOL
// Here is my conditionally compiled code
#else
// error
#endif
And now it's a short step to the typical c++ include guards. Copying from that wikipedia link, here is a grandparent.h file:
#ifndef GRANDPARENT_H
#define GRANDPARENT_H
struct foo {
int member;
};
#endif /* GRANDPARENT_H */
Now, even if you end up including this header twice, it will only be executed once.
I have a file A.h and B.h.
FileA.h is:
#define AA1 1
#define BB2 2
#define CC3 3
FileB.h is:
#include <FileA.h>
#define AA 1
#define BB 2
#define CC 3
#if AA != FileA.AA1 //is this the way to call AA1 variable in FileA??
#error "Mismatch variable"
#endif
I want to have a compiler error when if the definein fileA.h does not match the value in file FileB.h. Therefore I added a #error.
How would i reference the AA1 deine in FileA.cpp in the if statement in FileB.h?
is this line correct? #if AA != FileA.AA1
how would i call a define in another file in #if preprocessor???
You can't. #define macros are not member variables in the sense that you are thinking about them at all. If you want FileA and FileB to have similar #defines, you have to use naming conventions to differentiate them.
Typically you would prefix your #defines with an identifier, such as #define FILEA_AA 125 and #define FILEB_AA 300.
Then you can compare them with preprocessor directives as follows:
#if FILEA_AA == FILEB_AA
/* Code goes here */
#endif
You cannot do this with #define. #defineed identifier is not a variable. #define is a simple text replacement performed by the preprocessor before the compiler really gets started.
Simplistically what happens is something like this: Some file includes FileB.h. This effectively pastes FileB.h into the including file, replacing the include statement. Shortly thereafter the preprocessor finds the include of FileA.h and does the same thing: pastes in FileA.h. You wind up with something like:
#define AA 1
#define BB 2
#define CC 3
#define AA 1
#define BB 2
#define CC 3
#if AA != FileA.AA //is this the way to call AA1 variable in FileA??
#error "Mismatch variable"
#endif
This repeats the definitions. A decent compiler will spit out a warning if they do not match. For example, if I force a mismatch:
..\src\main.cpp:9:0: warning: "AA" redefined [enabled by default]
#define AA 2
^
..\src\main.cpp:3:0: note: this is the location of the previous definition
#define AA 1
I usually run with warnings treated as errors, so I wouldn't bother going any further. (Side note on why I take this draconian approach: A compiler error means the syntax is bad and the code is not executable. A warning means while the code can be executed it very likely won't do what you intend it to do. If the program's not going to work, why bother building it?)
So how do we get around this?
We take a lesson from the great and mighty Sauron and craft One Header to Rule them all. After all, If the values must be in lock-step, why repeat them? That way lies only madness and bugs. The only downside with this approach is filthy hobbitsies stealing the precious. Doesn't happen all that often.
Common definitions are moved to a header used by other headers. In this model, FileA.h and FileB.h both #include "coredefs.h"which contains all of the core definitions like AA and its ilk. Since this coredefs.h is included by pretty much everyone, read up on Include Guards.
coredefsh. is:
#ifndef COREDEFS_H
#define COREDEFS_H
#define AA1 1
#define BB2 2
#define CC3 3
#endif
FileA.h is:
#ifndef FILEA_H
#define FILEA_H
#include "coredefs.h"
// other File A stuff here
#endif
FileB.h is:
#ifndef FILEB_H
#define FILEB_H
#include "coredefs.h"
// other File B stuff here
#endif
#define TML_ID - No value is assigned to TML_ID. There's no problem in compilation or building executables. will this assign any default value like null to TML_ID or will TML_ID be considered undefined ?
This simply says that the macros is defined, so you can do this in main or any other function:
#ifdef TML_ID
printf("Defined!\n");
#else
printf("Undefined!\n");
#endif
#define doesn't assign a value to the macro. In fact, it's considered as a flag to tell the compiler that a specific macro has been defined.
You can imagine it as if you declare a variable without assigning any values. It will have a garbage value but it will reserve a space in the memory. But in case of a macro, the definition won't reserve a space. Only a hint for the compiler.
Without assigned a value, macros in this way are usually used to prevent including same .h file multiple times, this way:
#ifndef _FILENAME
#define _FILENAME
//declaration code
#endif
If some .cpp file includes, for example, two different .h files, which both include our .h file, then .cpp will have only one copy of declaration code, since second time _FILENAME macro will be DEFINED, and declaration code will be skipped.
#define MACRO
defines a macro named MACRO. It has no content, so if you wrote something like std::cout << MACRO you'd get an error because there's nothing there. This is often used to conditionally use new keywords:
#if CPP_VERSION_C11
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif
void f() NOEXCEPT {
// whatever
}
There are two other ways you can use such a macro. You can check whether it's defined:
#ifdef MACRO
// code for one branch
#else
// code for other branch
#endif
For that code, since MACRO has been defined, the preprocessor will look at the code in the first branch, and skip the code in the second branch. If MACRO had not been defined, it would skip the code in the first branch rather than the second. You can also do the same thing this way:
#if defined(MACRO)
or you can use it in a constant expression in a preprocessor directive:
#if MACRO
// code for one branch
#else
// code for other branch
#endif
here, MACRO gets the value 0, the #if sees the value 0, and the preprocessor skips the first branch. The same thing occurs in more complex expressions:
#if MACRO + 1 > 0
// code for one branch
#else
// code for other branch
#endif
Here, MACRO has the value 0, MACRO + 1 has the value 1, and the first branch will be selected.
In C and C++, when using a macro like so:
#if ( 1 == __MY_MACRO__ )
// Some code
#endif
The compiler will not catch if MY_MACRO is not defined and will consider it 0. This could cause a lot of hidden bugs when the design of the code is intended such that the macro must be defined (non-zero).
Is there away to get to compiler to report this, even if the compiler natively doesn't look for such thing?
Use #if defined(__MY_MACRO__) to test if the macro value is defined.
#ifndef __MY_MACRO__
#error "MY_MACRO NOT DEFINED"
#endif
You can use #ifdef or ifndef to check if a macro is defined of not.
Example :
#ifndef MY_MACRO
# error "MY_MACRO is not defined"
#endif
More informations can be found here : https://gcc.gnu.org/onlinedocs/cpp/Ifdef.html
I have to resort to
#if !defined( __MY_MACRO__ )
MACRO_NOT_DEFINED; //to cause compiler error
#endif
#if ( 1 == __MY_MACRO__ )
//code
#endif
Which looks rather ugly.
Someone I know came up with a clever 1 liner
#if ( (1/defined(_MY_MACRO__) && 1 == _MY_MACRO__ ) )
//code
#endif
If _MY_MACRO__ is not defined, it will cause divide by zero error.
If the macro is used as compile switch try this way.
in a configuration file:
#define FEATURE_1_ENABLED() (1)
#define FEATURE_2_ENABLED() (0)
in place you checking the value:
#if FEATURE_1_ENABLED()
// whatever
#endif
in contrast to your example this does show error when macro is not visible by mistake (at least in my ide)
I know the following 3 parts #define:
#define PI 3.4
which mean it will replace PI with 3.4.
But that's the meaning of 2 parts #define like this:
#define something
Will it replace something with null/empty string?
The following is the code example, I searched the file, only list the related lines
D:\mariadb\storage\pbxt\src\cache_xt.cc (23 hits)
Line 172: #ifdef xtPublic
Line 173: #undef xtPublic
Line 188: #define xtPublic
Line 325: xtPublic XTIndHandlePtr xt_ind_get_handle(..)
Line 378: xtPublic void xt_ind_release_handle(XTIndHandlePtr..)
Line 516: xtPublic xtBool xt_ind_copy_on_write(XTIndReferencePtr iref)
Line 597: xtPublic void xt_ind_lock_handle(XTIndHandlePtr handle)
Yes it meaning replace something with an empty string. But the important thing is now something is recognized by the preprocessor that it is "defined", so
#ifdef something
will pass after that #define (Line 172).
Also, it is common to use it for configurational or vendor-specific attributes (Line 325, ...), like
#if MSVC
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
EXPORT void f();
// expand to '__declspec(dllexport) void f()' in MSVC
// expand to 'void f()' in other compilers
Those declarations are usually given within header files, as a means of preventing double inclusion of the same file. These are also called include guards.
#define something will result into something just defined. It will not cause a compiler error. It is used usually like
void getValue(IN int& x, OUT int& y). If you do #define IN and #define OUT it will not give a compiler error and anybody will get to know x is input and y is output
One more use is like
#ifndef __ABC_H__
#define __ABC_H__
...
#endif
This is to prevent reinclusion of for eg. "abc.h"
Its is nothing but Pre-Processor Directive, the #define just will direct the Header files to the considered Library files or can declares the constants.
Yes, it replaces the preprocessor with empty string. It helps is self-documenting the code without writing lengthy comments.