How to test if preprocessor symbol is #define'd but has no value?
Soma macro magic:
#define DO_EXPAND(VAL) VAL ## 1
#define EXPAND(VAL) DO_EXPAND(VAL)
#if !defined(MYVARIABLE) || (EXPAND(MYVARIABLE) == 1)
Only here if MYVARIABLE is not defined
OR MYVARIABLE is the empty string
#endif
Note if you define MYVARIABLE on the command line the default value is 1:
g++ -DMYVARIABLE <file>
Here the value of MYVARIABLE is the empty string:
g++ -DMYVARIABLE= <file>
The quoting problem solved:
#define DO_QUOTE(X) #X
#define QUOTE(X) DO_QUOTE(X)
#define MY_QUOTED_VAR QUOTE(MYVARIABLE)
std::string x = MY_QUOTED_VAR;
std::string p = QUOTE(MYVARIABLE);
How to tell if a #define has a value or not
do I have to specify in documentation which to use?
Technically no, you don't. But you should.
You can easily normalise on checking for false by doing this:
#ifndef DISABLE_FEATURE
#define DISABLE_FEATURE false
#endif
// later
#if DISABLE_FEATURE == false
...
Normalising on checking for definedness is a bit trickier because you cannot compare an empty macro with a value. But it is possible. You can use macro magic such as this (expansion magic borrowed from here):
#define DO_EXPAND(VAL) VAL ## 1
#define EXPAND(VAL) DO_EXPAND(VAL)
#if defined(DISABLE_FEATURE) \
&& (EXPAND(DISABLE_FEATURE) == false)
#undef DISABLE_FEATURE
#endif
// later
#ifdef DISABLE_FEATURE
...
I recommend instead to stick to one way and to document that. In particular I recommend checking for definedness, and to ignore the value entirely.
Check if a constructed constant is #define'd
If we assume that include guards always looks like
#define NAME /* no more tokens here */
and if, as you said, any compile time error (rather than #error
exclusively) is acceptable, then you can do following:
#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) static int CAT(UNUSED_,__LINE__) = CAT(CAT(THENAMESPACE,CAT(_,x)),+1);
NAMESPACE(API_H)
Here, NAMESPACE(API_H)
tries to concatenate BLA_API_H
and +
using ##
.
This results in error: pasting "BLA_API_H" and "+" does not give a valid preprocessing token
except if BLA_API_H
is #define
d to 'no tokens'.
In presence of #define BLA_API_H
, NAMESPACE(API_H)
simply becomes
static int UNUSED_/*line number here*/ = +1;
If you settle for a less robust solution, you can even get nice error messages:
#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define TRUTHY_VALUE_X 1
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) CAT(CAT(TRUTHY_VALUE_,CAT(THENAMESPACE,CAT(_,x))),X)
#if !NAMESPACE(API_H)
#error "namespace not properly defined"
#endif
Here, if BLA_API_H
is defined, then #if !NAMESPACE(API_H)
expands to #if 1
.
If BLA_API_H
is not defined, then it expands to #if TRUTHY_VALUE_BLA_API_HX
, and TRUTHY_VALUE_BLA_API_HX
evaluates to false
due to being undefined.
The problem here is that if TRUTHY_VALUE_BLA_API_HX
accidentally turns out to be defined to something truthy, you'll get a false negatie.
Is there a way to both check a macro is defined and it equals a certain value at the same time
This may not work for the general case (I don't think there's a general solution to what you're asking for), but for your specific example you might consider changing this sequence of code:
#if(DEBUG_PRINT == 1)
printf("%s", "Testing");
#endif
to:
if (DEBUG_PRINT == 1) {
printf("%s", "Testing");
}
It's no more verbose and will fail to compile if DEBUG_PRINT
is not defined or if it's defined to be something that cannot be compared with 1
.
The C define with any value for non zero
A generic solution is likely impossible, but you can hack something together:
#define CAT(x, ...) CAT_(x, __VA_ARGS__)
#define CAT_(x, ...) x##__VA_ARGS__
#define CHECK_VALUE_CHECK_0 )(
#define CHECK_VALUE_FALSE(...) CHECK_VALUE_TRUE
#define CHECK_VALUE_TRUE() 1
#define CHECK_VALUE CHECK_VALUE_(CAT(CHECK_VALUE_CHECK_, VALUE))
#define CHECK_VALUE_(...) CHECK_VALUE_FALSE(__VA_ARGS__)
#if CHECK_VALUE
#error Value is 0.
#else
#error Value is not 0.
#endif
Now, if VALUE
is defined to 0
, the macro CHECK_VALUE
will expand to 1
. Otherwise it will expand to CHECK_VALUE_TRUE
, which as an unknown identifier, is considered falsey by #if
.
This solution is hacky:
- If
VALUE
starts with0,
, its causes a hard error. - If
VALUE
starts with something other than a letter or digit or_
(e.g.(
), it causes a hard error. - ...
Set macro to value, iff empty
If you know that only the values 0
, 1
or empty can occur you could use something like
#define some_impossible_macro 1
#define some_impossible_macro0 0
#define some_impossible_macro1 0
#define IS_EMPTY(X) some_impossible_macro ## X
Otherwise, for the general case this is a bit more complicated but doable. You could use P99_IS_EMPTY
from P99.
Is #if preprocessor macro running #ifdef behind the scenes in Objective-C?
It's not recommended to use #if VARIABLE
without checking that VARIABLE
has been defined.
When #if
evaluates the expression, it does the following:
It expands all macros in the expression (which means that an symbol which has not been
#define
d will be unchanged.)It parses the result as an integer arithmetic expression, replacing any identifier with the integer 0.
So if DEBUG
has not been #define
d as a macro,
#if DEBUG
will be the same as
#if 0
which will also have the same effect as #ifdef DEBUG
.
If you define DEBUG
on the command-line with -DDEBUG
, then there is an implicit
#define DEBUG 1
before the file is preprocessed, with the result that
#if DEBUG
is the same as
#if 1
which is also the same as #ifdef DEBUG
.
However. If you did the following:
#define DEBUG
#if DEBUG
// ... stuff
#endif
the the #if
will expand to:
#if
and you'll get an error message:
file.m:2:6: error: #if with no expression
As a result, it is unwise to use #if VARIABLE
, unless you know for sure that VARIABLE
has been defined as an integer.
Issues with using #ifdefs in C#
If you are using Visual Studio is pretty simple to do preprocessor directives.
- Select Project
- Properties
- Build
- On 'Conditional compilation symbols' put your wanted symbol and you should have access in all the assembly
If you are not using Visual Studio just follow this topic.
For learning purpose about preprocessor directives you can go to Tutorialspoint C# website.
To write code in C# using C++ approach you can use the following syntax:
#define Name_Value
#if (Name_value)
{
//code
}
If this doesn't fit your needs you can go with a configuration file where you can stack in all your key name - value and access them by ConfigurationManger.AppSettings["Key"]
Another way around this is to have a global enum
and assign values.
public enum DemoEnum
{
Name = Value
}
if(passedEnum == DemoEnum.Name)
{
// code
}
The solution you gave with the constants is not very flexible, because if your code changes you will have to create new constants and the image gets too blurry.
Using readonly properties you can switch values of 'const' in your approach.
public class Global
{
public readonly string Name;
public Global()
{
if(condition)
Name = 10;
else
Name = 30;
}
}
If I forgot an option feel free to comment :)
Related Topics
What Is the Purpose and Return Type of the _Builtin_Offsetof Operator
2D-Array as Argument to Function
C++/C Function Pointers That Return Void*
Copyfileex with Progress Callback in Qt
Portability of #Warning Preprocessor Directive
Project Euler #8, I Don't Understand Where I'm Going Wrong
Why Is There an Implicit Type Conversion from Pointers to Bool in C++
Retrieving File Descriptor from a Std::Fstream
Rand() Generating the Same Number - Even with Srand(Time(Null)) in My Main!
Case Insensitive String Comparison C++
Where Do Object File "Version References" Come From
Modifying a Char *Const String
Initializer-List-Constructing a Vector of Noncopyable (But Movable) Objects
Are Parent Class Constructors Called Before Initializing Variables
How to Convert Char* to Lpcwstr
How to Mix C++ and C Correctly
How to Pass the Windows Defender Smartscreen Protection
Why Does Std::Map Operator[] Create an Object If the Key Doesn't Exist