Preprocessors in C #if and #ifdef [closed] - c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
While learning about c preprocessor #if I came across this particular statement describing the term expression in its syntax given on gcc.gnu.org , syntax : -
#if *expression*
controlled text
#endif
Question:--Can someone explain what the following statement means in context of expression described in the above syntax :-
statement :-In C , expression may contain Identifiers that are not macros, which are all considered to be the number zero. This allows you to write #if MACRO instead of #ifdef MACRO, if you know that MACRO, when defined, will always have a nonzero value. Function-like macros used without their function call parentheses are also treated as zero.
In some contexts this shortcut is undesirable. The -Wundef option causes GCC to warn whenever it encounters an identifier which is not a macro in an #if.

In C , expression may contain Identifiers that are not macros, which are all considered to be the number zero.
This means that, if you have a #if directive such as:
#if X == 3
and X is not defined as a preprocessor macro, then it is replaced with 0, so the directive is processed as if it were:
#if 0 == 3
That is standard C behavior. GCC’s -Wundef option asks the compiler to warn you when this occurs.
There is one exception; the identifier defined is treated specially. If defined identifier or defined (identifier) appears in a #if directive, it is replaced by 1 or 0 according to whether identifier is a defined macro or not.
This allows you to write #if MACRO instead of #ifdef MACRO, if you know that MACRO, when defined, will always have a nonzero value.
Due to the above substitution, #if MACRO will become either #if replacement if MACRO is a defined object-like macro or #if 0 if not. Then we have the following cases:
MACRO is an object-like macro that expands to something that is not zero: #if MACRO evaluates it as true, and #ifdef MACRO evaluates its condition as true.
MACRO is an object-like macro that expands to something that is zero: #if MACRO evaluates it as false, and #ifdef MACRO evaluates its condition as true.
MACRO is not defined as an object-like macro: #if MACRO becomes #if 0 and is evaluated as false, and #ifdef MACRO evaluates its condition as false.
Thus, #if MACRO and #ifdef MACRO behave the same if MACRO is not an expression with value zero.
Note: An object-like macro has no arguments, as in:
#define MACRO (3+4)
and a function-like macro has arguments, as in:
#define MACRO(x) (3+(x))
Function-like macros used without their function call parentheses are also treated as zero.
If MACRO is defined as a function-like macro, then, in #if MACRO, no macro replacement is performed. This is because function-like macros are replaced only if they are followed by parentheses, as in #if MACRO(3). So, after being rejected for macro replacement, it proceeds to the substitution of identifiers with 0, becoming #if 0.

Related

C preprocessor parameter bracket covering the 'defined' keyword

#if (defined AAAA) //rather than- #if defined (AAAA)
#define BBB (0)
#else
#define BBB (1)
#endif
In the first line above, the parameter bracket includes the "defined" keyword, is there a scenario where this can cause any problem? I know the usual way would be-
#if defined (AAAA)
The syntax of expressions involving defined is specified in section 6.10.1p1 of the C standard (link goes to N1570, which is the closest approximation to the official text of C2011 that is publicly available for free). There are two forms:
defined identifier
or
defined ( identifier )
with exactly the same meaning. In other words, function-call parentheses around the argument of defined are optional.
In your hypothetical
#if (defined AAAA)
this is a use of the first form, with the optional argument parentheses omitted, and an extra set of grouping parentheses around the whole expression. It's interpreted the same as if you had put an extra set of grouping parentheses around a regular if expression containing a unary operation:
if (! variable) /* ... */
is the same as
if ((! variable)) /* ... */
In most of the C codebases I've worked on, the preferred style was to use exclusively defined identifier without the parentheses. I've never seen (defined identifier). It's possible that this used to be a more complicated construct, e.g.
#if (defined A && defined B) || defined C
where the parentheses are necessary, if only because nobody can remember which of && and || has higher precedence.
defined may be used as an ordinary operator inside #if directives.
C 2018 6.10.1 1 says:
The expression that controls conditional inclusion shall be an integer constant expression except that: identifiers (including those lexically identical to keywords) are interpreted as described below and it may contain unary operator expressions of the form
defined identifier
or
defined ( identifier )
which evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a #define preprocessing directive without an intervening #undef directive with the same subject identifier), 0 if it is not.
Thus, there is no requirement that a #if directive using defined have defined as the sole or top-level operator. It may appear anywhere in an expression, including inside parentheses or even as:
#if defined x + defined y + defined z == 2
which would test whether exactly two of x, y, and z are defined.
Also note that parentheses are not required; using defined (AAAA) instead of defined AAAA just adds clutter.

Working of conditional compilation #if and #else (and others) in c

I tried to write a program using some conditional compilation pre-processing directives instead of "if-else" as follows.
#include<stdio.h>
int main ()
{
int x;
scanf ("%d",&x);
#if (x==5)
printf ("x is 5");
#else
printf ("x not 5");
#endif
}
But the thing is, it always print the else part even though value of xis 5. My simplest question is----->WHY?
Is it possible to successfully complete this program (i.e taking value of x from user and check conditions using #if directive and print statement under #if).
During compilation it shows a warning "'x' is not defined, evaluates to 0". But x seems defined to me. Does that mean x should be defined using #define. Please explain me concept behind Conditional Compilation.
x is not an integer literal or an integer literal expression (integer literals + operators) or a macro expanding to those, so in a conditional, the preprocessor replaces it with 0 (6.10.1p4). 0==5 is false, so the #else branch is taken.
The preprocessor doesn't know about C declarations, types and such. It only works with tokens (and macros that ultimately expand to those).
6.10.1p4
After all replacements due to macro expansion and the defined unary
operator have been performed, all remaining identifiers (including
those lexically identical to keywords) are replaced with the pp-number
0, and then each preprocessing token is converted into a token.
Preprocessing takes place before the compilation. So preprocessor does not know anything about your C code or variables. You cant use any C variables in conditions.
Conditional compilation is for different purposes.
#define DEBUG
/* ....*/
#ifdef DEBUG
printf("Some debug value %d\n", val);
#endif
Operands in #if statements can be only constants, things defined with #define, and a special defined operator. Any other identifiers in the expression are replaced with 0. The x in your sample code is not defined with #define, so (x==5) becomes (0==0).
In the C 2018 standard, clause 6.10.1 tells us that evaluation of the expression in an #if statement includes:
Preprocessor macros (things defined with #define) are replaced according to their definitions.
Uses of the defined operator are replaced with 0 or 1.
Any remaining identifiers are replaced with 0.
Because the x in your sample code is not defined with #define, it is replaced with 0 in the #if statement. This results in (0==5), which is false, so code between the #if and the #else is skipped.
In a preprocessor statement, you cannot evaluate variables based on values that will be set during program execution.
It's the "pre-processor". "Pre" means "before".
You're trying to use a runtime value during preprocessing! The preprocessor of course has no access to that information during the build.
This problem isn't limited to runtime values, but is more fundamental. Even if you were trying to use a (named) compile-time constant such as constexpr int x = 2, you couldn't do that. These are two languages interleaving, like generating HTML with PHP; the HTML has no knowledge of PHP variables, and the PHP has no knowledge of what widgets the user clicks on the page. These are completely different execution contexts with no built-in interaction or cross-compatibility.

C Preprocessor #if handling of non-integer constant

I have the following code snippet to allow me flip easily between double and float representations of floating point values:
#define FLOATINGPOINTSIZE 64
#if FLOATINGPOINTSIZE == 64
typedef double FP_TYPE;
#define FP_LIT_SUFFIX
#else
typedef float FP_TYPE;
#define FP_LIT_SUFFIX f
#endif
At another location I had written the following:
/* set floating point limits used when initialising values that will be subject
* to the MIN() MAX() functions
*
* uses values from float.h */
#if FP_TYPE == double
#define FPTYPE_MAX DBL_MAX
#define FPTYPE_MIN DBL_MIN
#else
#define FPTYPE_MAX FLT_MAX
#define FPTYPE_MIN FLT_MIN
#endif
whereas I think I should have written:
#if FLOATINGPOINTSIZE == 64
I have -Wall compiler setting to give me plenty of warnings but this didn't get flagged up as an issue. Possibly -Wall is completely independent of the preprocessor though?
My question is how is the preprocessor interpreting:
#if FP_TYPE == double
The meaning is obvious to the programmer, but I'm not sure what the preprocessor makes of it?
Its got to be a bug right?
I have -Wall compiler setting to give me plenty of warnings but this
didn't get flagged up as an issue.
The code is valid, but you are right to be concerned.
My question is how is the
preprocessor interpreting:
#if FP_TYPE == double
Good question.
The meaning is obvious to the programmer, but I'm not sure what the
preprocessor makes of it?
The intended meaning seems obvious, and as the code's author, you know what you meant. But what you appear to have intended indeed is not how the preprocessor interprets that conditional.
The expression in a preprocessor conditional is interpreted as an integer constant expression. Just like in a C if statement, if the expression evaluates to 0 then the condition is considered false, and otherwise it is considered true. All macros in the expression are expanded before it is evaluated, and any remaining identifiers are replaced with 0. Details are presented in section 6.10.1 of the standard.
Supposing that there is no in-scope defnition of a macro named either FP_TYPE or double (and a typedef is not a macro definition), your conditional is equivalent to
#if 0 == 0
, which is always true.
Its got to be a bug right?
The preprocessing result will not be what you intended, so it's a bug in your code. The compiler, on the other hand, is correct to accept it.
The meaning is obvious to the programmer, but I'm not sure what the preprocessor makes of it?
Its got to be a bug right?
It's a bug from a user's point of view but it is not a bug in the preprocessor.
#if FP_TYPE == double
is interpreted as
#if 0 == 0
since neither FP_TYPE nor double is a known symbol for the pre-processor.
From https://gcc.gnu.org/onlinedocs/cpp/If.html#If:
Identifiers that are not macros, which are all considered to be the number zero. This allows you to write #if MACRO instead of #ifdef MACRO, if you know that MACRO, when defined, will always have a nonzero value. Function-like macros used without their function call parentheses are also treated as zero.

Function-like macro vs Object-like macro

I often get confused whether to use object-like or function-like macros. I have written about both here. So if the object-like macro's replacement list can be either literal, or list of literals. Then if we have an expression after the identifier we should use function-like macro right?
#define FIRST 1 //object-like
#define INCREASE_A_AND_B() do{++a;++b;}while(0) //functuion-like
#define ORED (FIRST | 5) //func or object? ORED or ORED()?
It would be much appreciated if someone shed some light when to use the one or the other way.
#define ORED (FIRST | 5)
Here, ORED is an object-like macro, because it was defined without parameter list. Try it:
ORED → (FIRST | 5)
ORED() → (FIRST | 5)() // Error: Object 5 not callable
The use of the macro depends on how it is defined. There's a special rule for macros, though: The opening parenthesis for an argument list to a macro must be given immediately after the macro name. Space characters between the macro name and the parenthesis define an object-like macro:
#define MACRO(X) // function-like macro hat expands to nothing
#define MACRO (X) // object-like macro that expands to (X)
Most compilers let you see what the code after preprocessing, i.e. after macro expansion looks like. gcc has the -E flag and Microsoft's cl has ´/E`.

sizeof() is not executed by preprocessor

#if sizeof(int) != 4
/* do something */
Using sizeof inside #if doesn't work while inside #define it works, why?
#define size(x) sizeof(x)/sizeof(x[0]) /*works*/
Nothing is evil - everything can be misused, or in your case misunderstood. The sizeof operator is a compiler feature, but compiler features are not available to the preprocessor (which runs before the compiler gets involved), and so cannot be used in #if preprocessor directives.
However, when you say:
#define size(x) sizeof(x)/sizeof(x[0])
and use it:
size(a)
the preprocessor performs a textual substitution that is handed to the compiler:
sizeof(a)/sizeof(a[0])
C "Preprocessor" Macros Only Evaluate Constants and Other Macros
The short answer is a preprocessor expression only provides a meaningful evaluation of an expression composed of other preprocessor macros and constants.
Try this, you will not get an error:
#if sizeof < 2
int f(int x) { return x; }
#endif
If you generate assembly, you will find that sizeof < 2 compiles the function and sizeof >= 2 does not. Neither returns an error.
What's going on? It turns out that, except for preprocessor macros themselves, all identifiers in a preprocessor ("macro") expression are replaced with 0. So the above #if is the same as saying:
#if Easter_Bunny < 2
or
#if 0 < 2
This is why you don't actually get any sort of error when mistakenly using the sizeof operator in a preprocessor expression.
As it happens, sizeof is an operator, but it's also an identifier, and identifiers that are not themselves macros all turn into 0 in preprocessor expressions. The preprocessor runs, at least conceptually, before the compiler. It can turn non-C syntax into C so at the point it is running, the C program hasn't even been parsed yet. It isn't possible to reference actual C objects yet: they don't exist.
And naturally, a sizeof in the replacement text of a definition is simply passed through to the compiler as, well, the replacement text where the macro is used.
The preprocessor cannot evaluate the results of the sizeof operator. That is calculated by the compiler, long after the preprocessor is finished.
Since the second expression results in a compile-time computation, it works. The first is an impossible test for the preprocessor.
#define is merely text replacement. #if being a conditional preprocessor directive evaluates sizeof() but at the time of preprocessing the preprocessor has no idea what sizeof() is. Preprocessor runs before the lexical analysis phase.
sizeof is replaced at compile time.
Preprocessing runs before compile starts.
The compiler doesn't touch either line. Rather, the preprocessor rips through the file, replacing any instances of size(x) with your macro. The compiler DOES see these replacements.
Preprocessor doesn't know sizeof operator, it just cannot understand it. So #if doesn't work, since it has to understand it to work, because it is a conditional conditional preprocessor; it needs to know whether it evaluates to true or false.
But #define doesn't need to understand sizeof, as #define is just for text replacement. Preprocessor searches size macro (defined in #define) in the source code, and replaces it with what it is defined to be, which is in your case sizeof(x)/sizeof(x[0]).
The reason it doesn't work is because the pre-processor macros are 'evaluated' in a pass before the code reaches the compiler. So in the if pre-processor directive, the sizeof(int) (actually the sizeof(int) != 4) cannot be evaluated because that is done by the compiler, not the pre-processor.
The define statement though, simply does a text substitution, and so when it comes to the compiler, everywhere you had 'size(x)' you would have 'sizeof(x)/sizeof(x[0])' instead, and then this evaluates there at the compile stage... at every point in the code where you had 'size(x)'
If you want to check the size of the integer in the processor, use your make system to discover the size of integer on your system before running the preprocessor and write it to a header file as e.g. #define SIZEOF_INT 4, include this header file and do #if SIZEOF_INT == 4
For example, if you use cmake, you can use the CMAKE_SIZEOF_INT variable which has the size of the integer which you can put in a macro.

Resources