Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do 'true' and 'false' have their usual meaning in preprocessor conditionals?

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".

like image 210
Borph Avatar asked Feb 08 '21 08:02

Borph


People also ask

What is conditional preprocessor?

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.

What is the use of conditional preprocessor directive in c#?

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 do preprocessor directive #if and #endif explain?

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.

What is conditional directive in C?

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.

What are conditionals in C preprocessor?

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.

Why is the antecedent always true in a conditional statement?

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.

What is the converse of a conditional proposition?

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?

What is a true or false statement in programming?

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.


Video Answer


2 Answers

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.

like image 119
iBug Avatar answered Oct 21 '22 08:10

iBug


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 the defined unary operator have been performed, all remaining identifiers and keywords, except for true and false, are replaced with the pp-number 0, 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 type bool 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.

like image 20
user3840170 Avatar answered Oct 21 '22 07:10

user3840170