Given a C++11 compiler, which #error
is the correct one it should end up with?
// no #includes!
#define SOMEMACRO true
#if SOMEMACRO
#error "it was true"
#else
#error "it was false"
#endif
Godbolt demo
Obviously I'm using #error
just as a test. I know true
and false
are defined in the language proper, but this is preprocessor context. In C99 it seems not to be recognised by the preprocessor.
I'm asking because it seems that all compilers I tried see it as 'true', while a static code analysis tool insists that true
isn't defined, implicitly false and ends up in "it was false".
A conditional is a directive that instructs the preprocessor to select whether or not to include a chunk of code in the final token stream passed to the compiler.
Preprocessor Directives in C# It allows testing a symbol or symbols to see if they evaluate to true. It allows to create a compound conditional directive, along with #if. It allows creating a compound conditional directive. Specifies the end of a conditional directive.
What does preprocessor directive #if and #endif explains? Explanation: The #if and #endif directives enable conditional compilation of a sequence of code based upon whether an expression involving one or more symbols evaluates to true. A symbol is true if it has been defined.
The conditional directives are meant to control the compilation process. By using them we may conditionally include certain statements of the program for compilation. If the condition is not met the statements are not included. These directives also help us not to include duplicate files in the program and cause error.
Preprocessor conditionals can test arithmetic expressions, or whether a name is defined as a macro, or both simultaneously using the special defined operator. A conditional in the C preprocessor resembles in some ways an if statement in C, but it is important to understand the difference between them.
Because the way a conditional statement is defined is such that only if The antecedent is True and the consequent false is the whole proposition false, this means, that all other pairings must be true . This follows because of the principle of bivalence.
A conditional proposition would be one of the form: . It’s converse would be: . Here we have that a conditional proposition will be true and its converse false, precisely in the case that is false and is true, as shown by the truth table below: What does the null and alternative hypothesis mean in a hypothesis test mean?
A statement evaluated as True or False is the simplest, most minor decision a program can make. It takes into account two or more factors and considers them to be either one or the other. True or False evaluations are so critical in programming that they have their own datatype - the boolean datatype.
In all ISO C++ standards, both true
and false
are keyword constants, just like nullptr
in C++11. So #if SOMEMACRO
= #if true
and the preprocessor will go to the truthy branch.
In C, however, neither true
nor false
is ever a keyword. They're macros defined to 1
and 0
respectively, as of C99 and with #include <stdbool.h>
. This does mean that however, if you don't include stdbool.h
, the compiler should complain about unrecognized identifiers for true
, false
etc. After including the header, #if SOMEMACRO
is now #if 1
, which is truthy in C.
For preprocessing, this quote from CppReference is meaningful:
Any identifier, which is not literal, non defined using
#define
directive, evaluates to 0.
So in your (probably C-oriented) static analysis tool, it sees true
as a non-#define
-defined identifier, and therefore evaluates true
to zero. You're not going to observe this behavior if you use a C++ analysis tool.
In that case, you probably shouldn't have missed the #include <stdbool.h>
in the first place, though.
According to [cpp.cond]/4 in the C++11 standard:
Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the
defined
unary operator), just as in normal text. […] After all replacements due to macro expansion and thedefined
unary operator have been performed, all remaining identifiers and keywords, except fortrue
andfalse
, are replaced with the pp-number0
, and then each preprocessing token is converted into a token. The resulting tokens comprise the controlling constant expression which is evaluated according to the rules of [expr.const] using arithmetic that has at least the ranges specified in [support.limits]. […] Each subexpression with typebool
is subjected to integral promotion before processing continues.
Emphasis mine; from the bolded passages it follows that bool
-typed expressions are meant to be supported in preprocessor conditions just like in the language proper, including bool
literals true
and false
. The [expr.const] section defining constant expressions is referred to from other sections that use it in non-preprocessing context, from which it follows that the evaluation rules are the same in the preprocessor and the language proper.
I’d assume similar language appears in all further revisions of the C++ standard, and probably in earlier ones too. In C, on the other hand, true
and false
are not keywords, but macros defined in stdbool.h
, so the preprocessor treats them just like any other token.
The usual practice is to use 1
and 0
for logical values in preprocessor expressions for maximum portability, and preferably to avoid directly referring to them entirely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With