I am passing a compiler option in makefile called DPATH, which is something like DPATH=/path/to/somefile. Based on this, I have to write a macro such that:-
#if "$(DPATH)"=="/path/to/x"
#error no x allowed
#endif
How do I compare DPATH with the string in a preprocessor conditional test?
It is not possible to do this in the preprocessor. #if can only evaluate integer expressions making no reference to functions or variables. All identifiers that survive macro expansion are replaced by zeroes, and a string constant triggers an automatic syntax error.
Without knowing more about your problem, I would suggest writing a tiny test program that is compiled and executed during the build, and Makefile goo to fail the build if the test doesn't pass.
#include <stdio.h>
#include <string.h>
int main(void)
{
if (!strcmp(DPATH, "/path/to/x") || some1 == 3 || some2 == 7 || ...)
{
fputs("bogus configuration\n", stderr);
return 1;
}
return 0;
}
and then
all : validate_configuration
validate_configuration: config_validator
if ./config_validator; then touch validate_configuration; else exit 1; fi
config_validator: config_validator.c
# etc
Related
#define TEST
int i = 1;
int main(int argc, char const *argv[]) {
#if (defined(TEST) && i)
printf("it is printed");
#endif
return 0;
}
Do I have to create another macro for i?
If you want the output if and only if both the macro and the condition on the global variable are true then do like this:
#if (defined(TEST))
if (i)
{ printf("it is printed");
}
#endif
Reason (agreeing with comment by Barmar):
Preprocessor directives are evaluated at compile time, variables are not available at that time.
As in the comments, macro definitions are expanded during the preprocessing stage, before the actual C code compilation.
But why this code compiles and what will be the result of it.
#if (defined(TEST) && i)
preprocessor tests for macro definition TEST. As it was defined, the result of this check is true
now the preprocessor is checking if macro definition (not the C variable!) i exists. As it does not, the whole expression in the #if is evaluated to false.
Generally :
#if a
checks if macro definition a exists and then if its value is != 0,
Consider the following - I want to check with #if #endif whether a
token is defined somewhere in the code.
I am using a CONCAT(input) macro that should glue the constant and changing parts of the token that I want to check.
Unfortunately, the approach presented below causes a compilation error:
error: missing binary operator before token "("
I have found the expressions that can be put inside a #if #endif block:
https://gcc.gnu.org/onlinedocs/cpp/If.html#If
And apparently it states that:
Macros. All macros in the expression are expanded before actual computation of the expression’s value begins.
It turns out that (CONCAT(test)) should be resolved, but it is not.
Is there any workaround allowing to resolve concatenated token names correctly in a conditional compilation block?
#include <stdio.h>
#define CONCAT(input) string##input
#define stringtest 1
int main(void)
{
#if defined(CONCAT(test)) && (CONCAT(test)==1)
printf("OK");
#else
printf("NOT");
#endif
return 0;
}
If you use just: #if CONCAT(test) == 1 it will work and is enought.
The statement #if defined(CONCAT(test)) does not work because CONCAT(test) will be evaluated to stringtest which will be evaluated to 1, and you can't use defined on a numerical constant.
A different situation came to my mind - what if I want to check whether the token is eg. != 1 Then if it is not defined anywhere, the condition will evaluate to true. So there would be no difference between token not defined and token being different than 1.
You could handle == 0 equal to not defined. So you could use: #if CONCAT(test) != 0 && CONCAT(test) != 1 where CONCAT(test) != 0 means defined(CONCAT(test)). That is the only alternative, because you can't get macro expansion work in a #ifdef or #if defined() statement, see this question which is very similar to yours.
The gcc documentation says:
Conditionals written like this:
#if defined BUFSIZE && BUFSIZE >= 1024
can generally be simplified to just #if BUFSIZE >= 1024, since if BUFSIZE is not defined, it will be interpreted as having the value zero.
Also it can be helpful if you check macro expansion by using gcc -E yourSource.cpp.
gcc --help:
-E Preprocess only; do not compile, assemble or link
You can't do that. Only literals can be used.
You should check for macro directly:
#include <stdio.h>
#define CONCAT(input) string##input
#define stringtest 1
int main(void) {
#if stringtest == 1
printf("OK");
#else
printf("NOT");
#endif
return 0;
}
Since you don't need defined check, you can use like this:
#define CONCAT(input) string##input
#define stringtest 1
int main(void) {
#if CONCAT(test) == 1
printf("OK");
#else
printf("NOT");
#endif
return 0;
}
I got the error Error[Pe018]: expected a ")" at CPU_state == cpuStateOff.
When I change cpuStateOff to 0 it's OK. I don't know why.
In my PERIPHERAL_APP.h:
#ifndef __PERIPHERAL_APP_H
#define __PERIPHERAL_APP_H
// CPU state
#define CPU_STATE_OFF 0;
#define CPU_STATE_ON 1;
#endif
In my main.c:
#include "PERIPHERAL_APP.h"
void main( void )
{
initMSP430();
_EINT();
for (;;)
{
if (cpuState == CPU_STATE_OFF ) // The error is hear
{
__bis_SR_register(LPM3_bits);
}
else
{
__bis_SR_register(LPM0_bits);
}
}
}
Preprocessor macros are not C statements, and therefore doesn't need a statement terminator like ;.
What happens is that when the preprocessor replaces the macro cpuStateOff it uses the whole body of the macro, i.e. 0; which results in code like
if (CPU_state == 0; ) // Code after macro replacement
Most compilers and environments have options to stop after preprocessing, if you use it you can see exactly what code the compiler "proper" will see.
MyMacros.h:
int const TESTING = 1;
#define INFO(MSG) fprintf(stderr, "INFO :: %s\n", MSG);
MyProgram.c:
#if TESTING
INFO("File 'data.dat' opened correctly.");
#endif
The message isn't printed to the screen. However if I do this:
#if TESTING < 1
It works and prints the message. Hunh???
You are confusing preprocessing and compiling.
The line int const TESTING = 1; is not understood by C preprocessor, it doesn't know the value of TESTING. In fact, neither the C compiler can use that value at the compile time (unlike C++ with better support of const expressions).
It is common pattern in C to define constants using the #define directive (again, unlike C++):
#define TESTING 1
And note the absence of a semicolon at the end of this line. Semicolons are required by the compiler, not the preprocessor.
I wish to add some conditional directive in my code to control different build, for example:
#if VERSION > 100
/* Compiling here */
#endif
The problem is that 'VERSION' is in other's code where I can't change. It was defined as a string:
#define VERSION "101"
I'm wondering if there's some sort of macro or directive which converts the string to number so I can simply do
#if STRING_TO_NUMBER(VERSION) > 100
/* Compiling here */
#endif
Is that possible please?
PS.
It seems my description is not quite clear. The main purpose of this requirement is to control the version branch. For example, in old version, pre-version 100, this program would like old_function(). After this version, all functions have been migrated to new_function. So I need to write codes like that:
#if VERSION >= 100
old_function();
#else
new_function();
#endif
#if VERSION >= 100
int old_function()
{
...
}
#else
int new_function()
{
...
}
#endif
You can see that only one of the function will be compiled. Therefore the condition must be decided in preprocessing stage, not in the runtime.
The tricky part is, the VERSION had been defined as a string, which brought this question.
If you need to interact with the pre-processor to set other #defines or conditionally #include different headers. Until you can get VERSION to be "fixed" to be an integer...
The only thing that I can think of for you to do is to create a tiny header file defining PROPER_VERSION and include it by naming each file as the version number. So here you would create:
100:
#define PROPER_VERSION 100
101:
#define PROPER_VERSION 101
102:
#define PROPER_VERSION 102
and then you would need to add the following:
#include VERSION
And then use PROPER_VERSION as you need
#if PROPER_VERSION > 100
...
Its not elegant, but I cannot see anything else you can do. You can auto-generate the VERSION file.
As long as you don't need to make declarations or preprocessor defines conditional on VERSION, and as long as you are confident that the VERSION string will just be an integer with no leading zeros, (both of which might be too much to ask for), you might be able to do this at compile time if your compiler has a reasonably effective constant expression evaluator.
For example, gcc 4.8 will optimize away the following if test, leaving only the appropriate arm:
if (strlen(VERSION) > 3 || (strlen(VERSION) == 3 && strcmp(VERSION, "100") > 0)) {
// code if VERSION is at least "101"
} else {
// code if VERSION is "100" or less
}
The fact that only one of the branches of the if statement survives the compilation is easily demonstrated by inserting a call to an undefined function in the non-used branch. With gcc (and clang), and with optimization enabled, no linker error is produced:
#include <stdio.h>
#include <string.h>
#define VERSION "101"
// This function is not available for linking
int unknown_function();
// This one is in standard library
int rand();
int main(void) {
int x;
if (strlen(VERSION) > 3 || (strlen(VERSION) == 3 && strcmp(VERSION, "100") > 0)) {
// code if VERSION is at least "101"
x = rand();
} else {
// code if VERSION is "100" or less
x = unknown_function();
}
printf("%d\n", x);
return 0;
}
(See it at http://ideone.com/nGLGTH)
In C++11, there is an even more clearly compile-time version. You can create a constexpr version of atoi. Combined with what some might call an abuse of templates, that allows for conditional declarations:
constexpr int const_atoi(const char* num, int accum=0) {
return *num ? const_atoi(num+1, accum*10 + (*num - '0')) : accum;
}
template<bool V_GT_100> struct MoreOrLess_Impl;
template<> struct MoreOrLess_Impl<false> {
// Old prototype
void doit(double x) {...}
};
template<> struct MoreOrLess_Impl<true> {
// New prototype
void doit(long double x) {...}
};
using MoreOrLess = MoreOrLess_Impl<(const_atoi(VERSION) > 100)>;
// ...
// ... MoreOrLess::doit(x) ...
(Silly example at http://ideone.com/H1sdNg)