Are enum values resolved in preprocess time or in compile time? - c

When are enum values resolved? In other words, is the following code snippet standard-compliant?
enum{
A,
B,
MAX
}
#if MAX > 42
# error "Woah! MAX is a lot!"
#endif

The preprocessor doesn't have anything to do with enums. But your example compiles without error, so what's going on with the #if MAX > 42 directive?
Whenever the preprocessor is handling a conditional directive, any identifiers that are not defined as macros are treated as 0. So assuming that MAX isn't defined elsewhere as a macro, your snippet of code is equivalent to:
enum{
A,
B,
MAX
}
#if 0 > 42
# error "Woah! MAX is a lot!"
#endif
From C99 6.10.1/3 "Conditional inclusion":
... After all replacements due to macro expansion and the defined
unary operator have been performed, all remaining identifiers are
replaced with the pp-number 0, and then each preprocessing token is
converted into a token. ...
The same wording is in the C89/C90 standard.

Related

Preprocessors in C #if and #ifdef [closed]

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.

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.

C Preprocessor: Evaluate macro early

Consider the following setup:
a.h
#define A 5
#define B A
#undef A
#define A 3
a.c
#include "a.h"
#include <stdio.h>
int main()
{
printf("%d\n", B);
return 0;
}
While this very reasonably prints 3, is there a way to make it print 5, i.e. do the substitution of 5 for A already at line two of a.h?
No, there's no way to do that. Unless you know all the possible values of A, and they are always integers, in which case you can laboriously test each one in turn:
#if A == 0
# define B 0
#elif A == 1
# define B 1
#elif A == 2
# define B 2
/* ... and a very long etc. */
#endif
If your use case only involves integers, you have more options. You could, for example, declare Bto be static const int or enum (depending on language) instead of a macro, which would obviously use the current value of the macro. If you really really want macros, the Boost preprocessing library has an implementation of the laborious sequence of #ifs above (with some cleverness to reduce the number of preprocessor statements needed to log(N) instead of N).
There is no macro substitution in the #define preprocessor directive; this fact is covered by §6.10 para. 7 of the C standard (§16 para. 6 of the C++ standard, with identical wording):
The preprocessing tokens within a preprocessing directive are not subject to macro expansion unless otherwise stated.
In the description of the #if and #include directives, the standard specifies that macro replacement does occur, which is why the #if solution above works (and the Boost implementation, which also uses a computed #include).
Yes. Boost's preprocessor library (a set of portable includes, not an extended preprocessor) includes support for "mutable" macro definitions. Instead of defining a macro to expand to a value directly, you can define it to expand to a reference a mutable slot, which can be changed because it expands the value "assigned" to it early. In this case you're less interested in the ability to change the value, than in the fact that this early expansion means it can grab the value out of A at a point ahead of both the use of B or the redefinition of A.
#include <boost/preprocessor/slot/slot.hpp>
#define A 5
#define B BOOST_PP_SLOT(1)
// "assign" A to B
#define BOOST_PP_VALUE A
#include BOOST_PP_ASSIGN_SLOT(1)
#undef A
#define A 3
#include "a.h"
#include <stdio.h>
int main()
{
printf("%d\n", B); // 5
return 0;
}
Support is limited to integers. It takes advantage of the fact that #if directives force expansion of any contained macros (so do #line and #error, although those are not very useful for this purpose), and uses them to build up an equivalent integer value for the slot being assigned to, stored in hidden backend macros. This way it can "extract" a value from A, and B can then refer to the value itself even if A changes or is removed.

C preprocessor #if expression

I am a bit confused on the type of expression we can use with the #IF preprocessor in the C language. I tried the following code, and it isn't working. Please explain and provide examples for expressions that can be used with the preprocessor.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
int c=1;
#if c==1
#define check(a) (a==1)?a:5
#define TABLE_SIZE 100
#endif
int main()
{
int a = 0, b;
printf("a = %d\n", a);
b = check(a);
printf("a = %d %d\n", a, TABLE_SIZE);
system("PAUSE");
return 0;
}
The preprocessor cannot use variables from the C program in expressions - it can only act on preprocessor macros. So when you try to use c in the preprocessor you don't get what you might expect.
However, you also don't get an error because when the preprocessor tries to evaluate an identifier that isn't defined as a macro, it treats the identifier as having a value of zero.
So when you hit this snippet:
#if c==1
#define check(a) (a==1)?a:5
#define TABLE_SIZE 100
#endif
The c used by the preprocessor has nothing to do with the variable c from the C program. The preprocessor looks to see if there's a macro defined for c. Since there isn't, it evaluates the following expression:
#if 0==1
which is false of course.
Since you don't appear to use the variable c in your program, you can do the following to get behavior in line with what you're trying:
#define C 1
#if C==1
#define check(a) (a==1)?a:5
#define TABLE_SIZE 100
#endif
(Note that I also made the macro name uppercase in keeping with convention for macro names.)
The preprocessor is run on the text, before any compilation is done. It doesn't know how to parse C. What you probably wanted instead of int c=1; was
#define C 1
and the test works the way you had it:
#if C == 1
The key here is that this is all defined before compile time. The preprocessor doesn't care about C variables, and certainly doesn't care what their values are.
Note that the convention is to have preprocessor macro names defined in ALL_CAPS.
In your example c is a compiler generated symbol, c has no value until run-time, whereas preprocessor expressions are evaluated at build-time (in fact as the name suggests before the compiler processes the code), so can only operate on pre-processor symbols which do exist at build time.
Moreover such expressions must be compile time constants, or in fact more exactly preprocessing time constant, since compiler constant expressions such as sizeof(...) for example are also not defined during pre-processing.
The preprocessor does not evaluate C variables. It "preprocesses" the source code before it is compiled and thus has its own language. Instead do this:
#define c 1
#if c==1
#define check(a) (a==1)?a:5
#define TABLE_SIZE 100
#endif
...

Resources