C - Macro contradiction - c

I just started learning C and I am not sure about how everything works. Some of examples simply looks weird to me and I cannot predict what would it print. I am programming in GCC, I mean it is my compiler, so every code I test is in GCC.
I understood pointers etc how that all stuff work, but also as you know there are macros. Macros are very weird, and I discovered one example I have no explanation about. For example look at this code particular code:
#include <stdio.h>
int main(void){
#define A 1
if(A == 0){
#define B 1
}
#ifdef B
printf("B is defined, which means that A == 0.\n");
#elif
printf("B isn't defined, which means that A == 1.\n");
#endif
printf("Value of A is %d\n", A);
return 0;
}
What should it print? Well, I though it is easy to guess, but now I see that it is not very easy. The result is not what i thought is.
This was my reasoning: we firstly define A to be 1 and then if A is 0 then define B to be 1. So, if B is defined it means that A == 0 and otherwise A == 1. But, surprisingly it prints:
B is defined, which means that A == 0.
Value of A is 1
What? It just printed a contradiction. I am not sure if this is some weird thing in GCC (because I have no visual studio or other compiler to test it). However, I am 99% sure I somehow misunderstood macros. I tried using variables instead of macros and it works properly.
Is it an issue, or did I simply misunderstand how macros work? Please keep in mind that I'm C beginner, so take it easy :).
Thank you in advance.

Macros are part of the preprocessor before the code is actually compiled. The compiler will search the code for all preprocessor directives and modify the code accordingly. So when the compiler gets to if(A == 0) {#define B 1} it has already been expanded to if(0 == 1) { }.
Macros makes it easy to configure an aspect of your code or to replace magic numbers into meaningful defines. For example:
#define DO_HOUR_CALCULATION
#define NUMBER_OF_SECONDS_PER_MINUTE (60)
#define NUMBER_OF_SECONDS_PER_HOUR (NUMBER_OF_SECONDS_PER_MINUTE * 60)
...
#ifdef DO_HOUR_CALCULATION
int hours = time / NUMBER_OF_SECONDS_PER_HOUR;
int minutes = (time % NUMBER_OF_SECONDS_PER_HOUR) / NUMBER_OF_SECONDS_PER_MINUTE;
#endif // defined(DO_TIME_CALCULATION)
Another use is to simplify a repeated or configurable task:
#define DEBUG
#ifdef DEBUG
#define DPRINTF(fmt, args...) printf(fmt, ## args)
#else
#define DPRINTF(args...) do {} while (0)
#endif
...
ret = read(fd, p_buffer, buf_size);
DPRINTF("read(fd) returned %d\n", ret);
Hope this helps you and happy coding!

Preprocessing directives are processed before non-preprocessing tokens are translated. And particularly, preprocessing directives are always evaluated at compile time, and never at runtime (cf. C standard, e.g. this draft).
If a token is a preprocessing token is defined as follows (all others are non-preprocessing tokens):
6.10 Preprocessing directives
(2) A preprocessing directive consists of a sequence of preprocessing
tokens that begins with a # preprocessing token that (at the start of
translation phase 4) is either the first character in the source file
(optionally after white space containing no new-line characters) or
that follows white space containing at least one new-line character
So if(A == 0) are non-preprocessing tokens (as the respective line does not start with a #, optionally with some space characters before), while #define B 1 is a preprocessing token.
According to the translation phases, preprocessing tokens are evaluated at translation time before the other tokens:
5.1.1.2 Translation phases
(4) Preprocessing directives are executed, macro invocations are
expanded, and _Pragma unary operator expressions are executed.
(7) ... The resulting tokens are syntactically and semantically
analyzed and translated as a translation unit.
So B will be defined already before if(A==0) will be translated, and particularly before if(A==0) will be executed. Thus, B will always be defined in your program.

The #define B 1 does not occur at run time. It happens at compile time. So #define B 1 is part of the compilation regardless of the result of A == 0, a run-time comparison
if(A == 0){
#define B 1
}
The following code
#ifdef B
printf("B is defined, which means that A == 0.\n");
#elif
printf("B isn't defined, which means that A == 1.\n");
#endif
is then the same as
printf("B is defined, which means that A == 0.\n");

Related

Defining a function as macro

I am trying to understand defining functions as macros and I have the following code, which I am not sure I understand:
#define MAX(i, limit) do \
{ \
if (i < limit) \
{ \
i++; \
} \
} while(1)
void main(void)
{
MAX(0, 3);
}
As I understand it tries to define MAX as an interval between 2 numbers? But what's the point of the infinite loop?
I have tried to store the value of MAX in a variable inside the main function, but it gives me an error saying expected an expression
I am currently in a software developing internship, and trying to learn embedded C since it's a new field for me. This was an exercise asking me what the following code will do. I was confused since I had never seen a function written like this
You are confused because this is a trick question. The posted code makes no sense whatsoever. The MAX macro expands indeed to an infinite loop and since its first argument is a literal value, i++ expands to 0++ which is a syntax error.
The lesson to be learned is: macros are confusing, error prone and should not be used to replace functions.
You have to understand that before your code gets to compiler, first it goes through a preprocessor. And it basically changes your text-written code. The way it changes the code is controlled with preprocessor directives (lines that begin with #, e.g. #include, #define, ...).
In your case, you use a #define directive, and everywhere a preprocessor finds a MAX(i, limit) will be replaced with its definition.
And the output of a preprocessor is also a textual file, but a bit modified. In your case, a preprocessor will replace MAX(0, 3) with
do
{
if (0 < 3)
{
0++;
}
} while(1)
And now the preprocessor output goes to a compiler like that.
So writing a function in a #define is not the same as writing a normal function void max(int i, int limit) { ... }.
Suppose you had a large number of statements of the form
if(a < 10) a++;
if(b < 100) b++;
if(c < 1000) c++;
In a comment, #the busybee refers to this pattern as a "saturating incrementer".
When you see a repeated pattern in code, there's a natural inclination to want to encapsulate the pattern somehow. Sometimes this is a good idea, or sometimes it's fine to just leave the repetition, if the attempt to encapsulate it ends up making things worse.
One way to encapsulate this particular pattern — I'm not going to say whether I think it's a good way or not — would be to define a function-like macro:
#define INCR_MAX(var, max) if(var < max) var++
Then you could say
INCR_MAX(a, 10);
INCR_MAX(b, 100);
INCR_MAX(c, 1000);
One reason to want to make this a function-like macro (as opposed to a true function) is that a macro can "modify its argument" — in this case, whatever variable name you hand to it as var — in a way that a true function couldn't. (That is, if your saturating incrementer were a true function, you would have to call it either as incr_max(&a, 10) or a = incr_max(a, 10), depending on how you chose to set it up.)
However, there's an issue with function-like macros and the semicolon at the end. I'm not going to explain that whole issue here; there's a big long previous SO question about it.
Applying the lesson of that other question, an "improved" INCR_MAX macro would be
#define INCR_MAX(var, max) do { if(var < max) var++; } while(0)
Finally, it appears that somewhere between your exercise and this SO question, the while(0) at the end somehow got changed to while(1). This just about has to have been an unintentional error, since while(1) makes no sense in this context whatsoever.
Yeah, there's a reason you don't understand it - it's garbage.
After preprocessing, the code is
void main(void)
{
do
{
if ( 0 < 3 )
{
0++;
}
} while(1);
}
Yeah, no clue what this thing is supposed to do. The name MAX implies that it should evaluate to the larger of its two arguments, a la
#define MAX(a,b) ((a) < (b) ? (b) : (a))
but that's obviously not what it's doing. It's not defining an interval between two numbers, it's attempting to set the value of the first argument to the second, but in a way that doesn't make a lick of sense.
There are three problems (technically, four):
the compiler will yak on 0++ - a constant cannot be the operand of the ++ or -- operators;
If either i or limit are expressions, such as MAX(i+1, i+5) you're going to have the same problem with the ++ operator and you're going to have precedence issues;
assuming you fix those problems, you still have an infinite loop;
The (technical) fourth problem is ... using a macro as a function. I know, this is embedded world, and embedded world wants to minimize function call overhead. That's what the inline function specifier is supposed to buy you so you don't have to go through this heartburn.
But, okay, maybe the compiler available for the system you're working on doesn't support inline so you have to go through this exercise.
But you're going to have to go to the person who gave you this code and politely and respectfully ask, "what is this crap?"

Defining C macros in preprocessor if statements

Below I change the value of the function that I call depending on the value of INPUT:
#include <stdio.h>
#define INPUT second
#if INPUT == first
#define FUNCTOCALL(X) first(X)
#elif INPUT == second
#define FUNCTOCALL(X) second(X)
#endif
void first(int x) {
printf("first %d\n", x);
}
void second(int x) {
printf("second %d\n", x);
}
int main() {
FUNCTOCALL(3);
return 0;
}
However, the output is first 3, even if INPUT is equal to second, as above. In fact, the first branch is always entered, regardless of the value of INPUT. I'm completely stumped by this - could someone explain what stupid mistake I'm making?
The c preprocessor only works on integer constant expressions in its conditionals.
If you give it tokens it can't expand (such as first or second where first and second aren't macros)
it'll treat them as 0 and 0 == 0 was true last time I used math. That's why the first branch is always taken.
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. ...
You have no macros first and second defined. Be aware that the pre-processor is not aware of C or C++ function names!* In comparisons and calculations (e. g. #if value or #if 2*X == Y), macros not defined (not defined at all or undefined again) or defined without value evaluate to 0. So, as first and second are not defined, INPUT is defined without value, and the comparison in both #if expressions evaluates to 0 == 0...
However, if you did define the two macros as needed, they would collide with the C function names and the pre-processor would replace these with the macro values as you just defined them, most likely resulting in invalid code (e. g. functions named 1 and 2)...
You might try this instead:
#define INPUT SECOND
#define FIRST 1
#define SECOND 2
#if INPUT == FIRST
#define FUNCTOCALL(X) first(X)
#elif INPUT == SECOND
#define FUNCTOCALL(X) second(X)
#else
# error INPUT not defined
#endif
Note the difference in case, making the macro and the function name differ.
* To be more precise, the pre-processor is not aware of any C or C++ tokens, so it does not know about types like int, double, structs or classes, ... – all it knows is what you make it explicitly aware of with #define, everything else is just text it operates on and, if encountering some known text nodes, replacing them with whatever you defined.

C macros using enum

I am trying to use #if macros by defining the type of operation to invoke the right code, So i made a very simple example similar to what I am trying to do:
#include <stdio.h>
enum{ADD,SUB,MUL};
#define operation ADD
int main()
{
int a = 4;
int b = 2;
int c;
#if (operation == ADD)
c = a+b;
#endif
#if (operation == SUB)
c = a-b;
#endif
#if (operation == MUL)
c = a*b;
#endif
printf("result = %i",c);
return 0;
}
But unfortunately that does not work I get the following result = 8... if I replace The operation with numbers it works fine .... But i want it to work as it is described above.
Any help
The preprocessor is a step that is (in a way) done before the actual compiler sees the code. Therefore it has no idea about enumerations or their values, as they are set during compilation which happens after preprocessing.
You simply can't use preprocessor conditional compilation using enumerations.
The preprocessor will always consider that as false:
#if IDENT == IDENT
It can only test for numeric values.
Simplify your code and feed it to the preprocessor:
enum {ADD,SUB,MUL};
#define operation ADD
int main()
{
(operation == ADD);
}
The result of the preprocessor output is:
enum {ADD,SUB,MUL};
int main()
{
(ADD == ADD);
}
As you see, the enumerate value hasn't been evaluated. In the #if statement, that expression is just seen as false.
So a workaround would be to replace your enumerate by a series of #define:
#define ADD 1
#define SUB 2
#define MUL 3
like this it works. Output of preprocessor output is now:
int main()
{
int a = 4;
int b = 2;
int c;
c = a+b;
# 28 "test.c"
printf("result = %i",c);
return 0;
}
the solution is:
either rely at 100% on the preprocessor (as the solution above suggests)
or rely at 100% on the compiler (use enums and real if statements)
As others have said, the preprocessor performs its transformations at a very early phase in compilation, before enum values are known. So you can't do this test in #if.
However, you can just use an ordinary if statement. Any decent compiler with optimization enabled will detect that you're comparing constants, perform the tests at compile time, and throw out the code that will never be executed. So you'll get the same result that you were trying to achieve with #if.
But i want it to work as it is described above.
You seem to mean that you want the preprocessor to recognize the enum constants as such, and to evaluate the == expressions in that light. I'm afraid you're out of luck.
The preprocessor knows nothing about enums. It operates on a mostly-raw stream of tokens and whitespace. When it evaluates a directive such as
#if (operation == SUB)
it first performs macro expansion to produce
#if (ADD == SUB)
. Then it must somehow convert the tokens ADD and SUB to numbers, but, again, it knows nothing about enums or the C significance of the preceding code. Its rule for interpreting such symbols as numbers is simple: it replaces each with 0. The result is that all three preprocessor conditionals in your code will always evaluate to true.
If you want the preprocessor to do this then you need to define the symbols to the preprocessor. Since you're not otherwise using the enum, you might as well just replace it altogether with
#define ADD 1
#define SUB 2
#define MUL 3
If you want the enum, too, then just use different symbols with the preprocessor than you use for the enum constants. You can use the same or different values, as you like, because never the twain shall meet.
Another solution would be to have the enum in an included header file.

How does the C preprocessor handle circular dependencies?

I want to know how the C preprocessor handles circular dependencies (of #defines). This is my program:
#define ONE TWO
#define TWO THREE
#define THREE ONE
int main()
{
int ONE, TWO, THREE;
ONE = 1;
TWO = 2;
THREE = 3;
printf ("ONE, TWO, THREE = %d, %d, %d \n",ONE, TWO, THREE);
}
Here is the preprocessor output. I'm unable to figure out why the output is as such. I would like to know the various steps a preprocessor takes in this case to give the following output.
# 1 "check_macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "check_macro.c"
int main()
{
int ONE, TWO, THREE;
ONE = 1;
TWO = 2;
THREE = 3;
printf ("ONE, TWO, THREE = %d, %d, %d \n",ONE, TWO, THREE);
}
I'm running this program on linux 3.2.0-49-generic-pae and compiling in gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5).
While a preprocessor macro is being expanded, that macro's name is not expanded. So all three of your symbols are defined as themselves:
ONE -> TWO -> THREE -> ONE (not expanded because expansion of ONE is in progress)
TWO -> THREE -> ONE -> TWO ( " TWO " )
THREE -> ONE -> TWO -> THREE ( " THREE " )
This behaviour is set by §6.10.3.4 of the C standard (section number from the C11 draft, although as far as I know, the wording and numbering of the section is unchanged since C89). When a macro name is encountered, it is replaced with its definition (and # and ## preprocessor operators are dealt with, as well as parameters to function-like macros). Then the result is rescanned for more macros (in the context of the rest of the file):
2/ If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced…
The clause goes on to say that any token which is not replaced because of a recursive call is effectively "frozen": it will never be replaced:
… These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
The situation which the last sentence refers rarely comes up in practice, but here is the simplest case I could think of:
#define two one,two
#define a(x) b(x)
#define b(x,y) x,y
a(two)
The result is one, two. two is expanded to one,two during the replacement of a, and the expanded two is marked as completely expanded. Subsequently, b(one,two) is expanded. This is no longer in the context of the replacement of two, but the two which is the second argument of b has been frozen, so it is not expanded again.
Your question is answered by publication ISO/IEC 9899:TC2 section 6.10.3.4 "Rescanning and further replacement", paragraph 2, which I quote here for your convenience; in the future, please consider reading the specificaftion when you have a question about the specification.
If the name of the macro being replaced is found during this scan of the replacement list
(not including the rest of the source file’s preprocessing tokens), it is not replaced.
Furthermore, if any nested replacements encounter the name of the macro being replaced,
it is not replaced. These nonreplaced macro name preprocessing tokens are no longer
available for further replacement even if they are later (re)examined in contexts in which
that macro name preprocessing token would otherwise have been replaced.
https://gcc.gnu.org/onlinedocs/cpp/Self-Referential-Macros.html#Self-Referential-Macros answers the question about self referential macros.
The crux of the answer is that when the pre-processor finds self referential macros, it doesn't expand them at all.
I suspect, the same logic is used to prevent expansion of circularly defined macros. Otherwise, the preprocessor will be in an infinite expansion.
In your example you do the macro processing before defining
variables of the same name, so regardless of what the result
of the macro processing is, you always print 1, 2, 3!
Here is an example where the variables are defined first:
#include <stdio.h>
int main()
{
int A = 1, B = 2, C = 3;
#define A B
#define B C
//#define C A
printf("%d\n", A);
printf("%d\n", B);
printf("%d\n", C);
}
This prints 3 3 3. Somewhat insidiously, un-commenting #define C A changes the behaviour of the line printf("%d\n", B);
Here's a nice demonstration of the behavior described in rici's and Eric Lippert's answers, i.e. that a macro name is not re-expanded if it is encountered again while already expanding the same macro.
Content of test.c:
#define ONE 1, TWO
#define TWO 2, THREE
#define THREE 3, ONE
int foo[] = {
ONE,
TWO,
THREE
};
Output of gcc -E test.c (excluding initial # 1 ... lines):
int foo[] = {
1, 2, 3, ONE,
2, 3, 1, TWO,
3, 1, 2, THREE
};
(I would post this as a comment, but including substantial code blocks in comments is kind of awkward, so I'm making this a Community Wiki answer instead. If you feel it would be better included as part of an existing answer, feel free to copy it and ask me to delete this CW version.)

Preprocessor #if directive

I am writing a big code and I don't want it all to be in my main.c so I wrote a .inc file that has IF-ELSE statement with function and I was wondering can it be written like this:
#if var==1
process(int a)
{
printf("Result is: %d",2*a);
}
#else
process(int a)
{
printf("Result is: %d",10*a);
}
#endif
I tried to compile it but it gives me errors or in best case it just goes on the first function process without checking the var variable (it is set to 0).
The preprocessor doesn't "know" the value of any variable, because it does its work even before compilation, not at runtime.
In the condition of a preprocessor #if you can only evaluate #define'd symbols and constant expressions.
The particular example you are showing can be simply converted to:
printf("Result is: %d", (var == 1 ? 2: 10) * a);
Just to complete. For a standard conforming compiler your code would always be correct. In #if expression evaluations all identifiers that are not known to the preprocessor are simply replaced with 0 (or false if you want). So in your particular case, if var is just a variable and not a macro, the result would always be the second version of your function.
For the error that you report for MS: I did know that the MS compilers aren't standard conforming, but I wasn't aware that they don't even fulfill such basic language requirements.
This is what you want:
process(int a)
{
if (var == 1)
printf("Result is: %d",2*a);
else
printf("Result is: %d",10*a);
}
It is important to remember that the preprocessor is its own program and not a part of the program you are writing. The variable "var" (or whatever var represents here) is not in the the namespace of the preprocessor's identifiers.

Resources