Why is the macro calling another macro showing error? - c

I wrote the following program and surprising it shows a compilation error that
'X' undeclared in exapansion of macro.
The code in c is:
#include<stdio.h>
#define X (4+Y)
#define Y (X+3)
int main()
{
printf("ds", "ds");
printf("%d\n", 4*X+2);
return 0;
}
I accept that this results in a kind of infinite macro replacement, but if that was an error, that should have been a run time error(truly speaking no error at all). Am I correct? If not, please correct me and explain me where I am getting it wrong?
EDIT: I am surprised that the following code however works perfectly:
#include<stdio.h>
#define X (4+Y)
#define Y 4
int main()
{
printf("ds", "ds");
printf("%d\n", 4*X+2);
return 0;
}

The C preprocessor does not expand a macro while that macro is being expanded (including indirectly through another macro). So in the expansion of Y inside the expansion of X, the preprocessor leaves X as is, and thus you get an undefined variable error.
Not only does this prevent infinite expansion loops, it also provides a useful feature. Suppose, for example, that you want to write a macro which "wraps" an existing function:
#define my_function(x, y) do { \
fputs("Calling my_function\n", stderr); \
my_function(x, y); \
while(0);
The fact that my_function is not expanded inside its own expansion makes it possible to wrap the function with a macro with the same name, thereby avoiding source modifications.
For any passing language lawyers, the standard specifies (§6.10.3.4/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. 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.

Creating .I file of your code in main.c file using gcc -E -o main.I main.c then we get a file which contains as below
int main()
{
printf("ds", "ds");
printf("%d\n", 4*(4+(X+3))+2);
return 0;
}
Hence macros just replaces the value. So in the expansion of Y inside the expansion of X, the preprocessor leaves X as is.
Hence as X is undefined error occurs.

Related

Why is the output different in these two scenarios

Please give me full description....
The first snippet of code has the 'function call' (macro invocation) before the increment operator, and second one has the function call after the increment operator.
#include <stdio.h>
#define square(x) x*x
int main()
{
int a,b=3;
a=square (b)++;
printf("%d%d",a,b);
return 0;
}
output:
124
why is 124 returned here
#include <stdio.h>
#define square(x) x*x
int main()
{
int a,b=3;
a=square (b++);
printf("%d%d",a,b);
return 0;
}
output:
125
and 125 here?
The thing to keep in mind is that macros provide simple substitution of preprocessor tokens. In particular, they may evaluate their arguments more than once, and if not guarded by parentheses, they may produce unintended reassociation.
In the first example, we have
a=square (b)++;
This expands to:
a=b*b++;
This is actually undefined behavior, since the b and b++ are unsequenced, and b++ modifies b. In your case, you are seeing 12 and 4 for a and b, so it would seem that the first value of b is picking up the incremented value, so you're getting 4*3, but you can't count on this behavior. The final value of b is 4 since it is incremented once.
In the second example, we have:
a=square (b++);
This expands to:
a=b++*b++;
This is again undefined behavior. In your case, it appears that you're getting 4*3 (or 3*4), but again, you can't count on this behavior. The final value of b is 5 since it is incremented twice, but this too is undefined behavior.
In addition to Tom's answer, which explains what is happening, here is an example of how you could define a macro for squaring a number safely:
#define SQR(x) ( \
{ \
__auto_type x_ = (x); \
\
x_ * x_; \
} \
)
It only has an appearance of x, and therefore it doesn't evaluate it twice. The copy x_ is used instead. Note that variables created in a macro may conflict with other variables created in the function that calls the macro. To avoid name collisions you use special names that shouldn't be used in normal code such as a trailing _.
With this macro, this:
a = SQR(b++);
will be equivalent to this:
a = SQR(b);
b++;
Warning: This works on some compilers as an extension (GCC for example), but it is not standard C.
Another option, if you want standard C, is to use an inline function. It is ok if you want it to work on just one type (there is _Generic in C11, but I never used it, so no idea).

mixture of string and number in macro

I want to use this macro to put (if 'i' is greater than zero) the symbol '^' and the number I pass (i) to the macro
#define ESP(i) ((i>0) ? ("^"(i)) : "")
I want to call it in this way
printf("%+d%s", n1, ESP(i));
where 'i' is the index of a cycle, but the compilation reports me errors;
how can I modify the code to be right?
Somewhat dirty but should work:
#include <stdio.h>
#define DYNFORMAT(n, i) (i>0) ?"%+d%s%d\n" :"%+d%s%s\n", n, (i>0) ?"^" :"", (i>0) ?i :""
int main(void)
{
int i = 0;
printf(DYNFORMAT(42, i));
i = 1;
printf(DYNFORMAT(42, i));
}
This should print:
+42
+42^1
Disclaimer: I am not sure whether this conforms to the Standard and how to get rid of the warning(s) it gives during compilation.
The clean approach would be to use two calls to printf().
This can be implemented as a macro or a function.
As I love the pre-processor, the macro version here:
#define PRINT_ESP(n, i) \
do { \
if (i = 0) \
printf("%+d", n); \
else \
printf("%+d^%d", n, i); \
} while (0);
Macros operate at compile time, not at run time. They can perform a variety of text-mangling tricks, but they do not evaluate anything. (They can certainly, however, expand to code that evaluates something.) Putting the formatted value of variable i into a string involves evaluating i; no macro can do this.
You could instead expand the scope of the macro to include the whole printf() call:
#define PRINT_ESP(n1, i) do { \
printf(((i > 0) ? "%+d^%d" : "%+d"), n1, i); \
} while (0)
Alternatively, you could use a macro to express just the format selection incorporated into the above macro definition, or you could just put the full printf() call above directly into your code.
All of these variations are based on the fact that arguments in excess of those required by the given format are evaluated prior to the call, but ignored by printf() itself.
You don't need the (i) after the "^". Change your macro to this and it should work #define ESP(i) ((i>0) ? ("^") : ("")). Then in your printf statement if you want to print the value of i after the "^" then have something like this printf("%s%d", ESP(i), i); As far as I know I don't think you can format a string to include an integer inside a macro since that would require calling other functions, so you have to bring the i into the string inside your printf.

Macro output explanation

When I run the following code,
#include<stdio.h>
#define X (4+Y)
#define Y (X+3)
int main()
{
printf("%d",4*X+2);
return 0;
}
I am getting the following output:
Error: Undefined symbol 'X'
Can someone please explain the output?
It is because the macro expects and argument since its defined with parentheses.
You would need to define it as
#define X 4+Y and #define Y X+3. Then you would run into another trouble because of cyclic definition in macros.
To be even more correct, as Drew suggested; when the example would be compilable when defining macros one usually puts the parentheses around expression to ensure expected operator precedence.
So your best shot would be:
#define X (4+Y)
#define Y (X+3)
Very close to your initial example, just a space character between name of a macro and its definition. However, it is still impossible to properly expand the macro due to the cyclic reference.
How to check what happened:
You can use gcc -E, which outputs a pre-processed file. It generates lots of output so I used tail. I also used 2>err to redirect error stream to a file, so the output is clear.
luk32:~/projects/tests$ gcc -E ./cyclic_macro_with_no_spaces.c 2> err | tail -n 6
int main()
{
printf("%d",4*X+2);
return 0;
}
luk32:~/projects/tests$ gcc -E ./cyclic_macro.c 2> err | tail -n 6
int main()
{
printf("%d",4*(4+(X+3))+2);
return 0;
}
In 1st example the X did not expand at all. While in the latter both macros got expanded, although only one. Giving the same output that Geoffrey presented in his answer.
Whether no space is a typo or not there is an undefined symbol 'X'. For different reason that are possible to trace by analyzing err files.
If the macros are left as invalid function-like macros, they are not getting expanded at all because you did not call it with parentheses. So X is never replaced with anything by the pre-processor, and is the reason for the Undefined symbol 'X' in your sample code.
If you wanted this to be expanded you would have to call it with parentheses like this:
printf("%d",4*X()+2);
This though would just error out when pre-processed as 4+Y and X+3 are not valid macro parameter names.
If your answer is corrected somewhat so that those defines are proper defines, and not function-like macros, ie:
#define X (4+Y)
#define Y (X+3)
You have a circular reference between the defines...
X -> Y -> X... etc.
Since it will only expand the macro once, it is getting expanded to
printf("%d",4*(4+(X+3))+2);
This explains why X is the undefined symbol in this use case.
You miss spaces
#define X (4+Y)
#define Y (X+3)

Macro expansion for macros with arguments vs. variables with the same name

Consider the following C program (ignore the double side-effect issue):
#define max(a, b) (a>b?a:b)
int main(void){
int max = max(5,6);
return max;
}
The GCC preprocessor turns this into:
int main(void){
int max = (5>6?5:6);
return max;
}
Which is quite nice, since you don't have to worry about unintentional collisions between max and max(). The GCC manual says:
A function-like macro is only expanded if its name appears with a pair of parentheses after it. If you write just the name, it is left alone
Is this standardized or just something done by convention?
Yes, the behavior here is well-defined.
Your macro max is a function-like macro (i.e., when you define it, its name is followed immediately by a left parenthesis and it takes arguments).
A use of max later in your code is only an invocation of that macro if the use of max is followed by a left parenthesis. So, these would not invoke the max macro:
int max;
max = 42;
But these would all invoke the max macro:
max(1, 2)
max (1, 2)
max
(
1, 2
)
max()
(Note that the last line is ill-formed because the number of arguments does not match the number of parameters. This is still a macro invocation, though, and would cause a compilation error.)
This behavior is mandated by the C langauge standard. C99 §6.10.3/10 states that after a function-like macro has been defined,
Each subsequent instance of the function-like macro name followed by a ( as the next preprocessing token introduces the sequence of preprocessing tokens that is replaced by the replacement list in the definition (an invocation of the macro).

Scope of #define preprocessor in C

The scope of #define is till the end of the file. But where does it start from.
Basically I tried the following code.
#include<stdio.h>
#include<stdlib.h>
#define pi 3.14
void fun();
int main()
{
printf("%f \n",pi);
#define pi 3.141516
fun();
return 0;
}
void fun(){
printf("%f \n",pi);}
The output of the above program comes out to be
3.140000
3.141416
Considering preprocessing for main the value of pi should be 3.141516
and outside main 3.14. This is incorrect but please explain why.
The C preprocessor runs through the file top-to-bottom and treats #define statements like a glorified copy-and-paste operation. Once it encounters the line #define pi 3.14, it starts replacing every instance of the word pi with 3.14. The pre-processor does not process (or even notice) C-language scoping mechanisms like parenthesis and curly braces. Once it sees a #define, that definition is in effect until either the end of the file is reached, the macro is un-defined with #undef, or (as in this case) the macro is re-defined with another #define statement.
If you are wanting constants that obey the C scoping rules, I suggest using something more on the lines of const float pi = 3.14;.
The scope of a #define is from the occurrence, to the end of the file (or a corresponding #undef), regardless of any intervening C scopes.
When you have preprocessor question:
gcc -E foo.c > foo.i; vim foo.i
Preprocessor has no concept of "scope" -- it manipulates the text of the program, without any idea of what the text is
Symbol is defined from its definition until the end of the compilation unit (a source file and and files it includes)
Here is what roughly looks like after the preprocessor done with your file:
void fun();
int main()
{
printf("%f \n",3.14);
fun();
return 0;
}
void fun(){
printf("%f \n",3.141516);}
These are the lines that go to the compiler for compilation(I discarded many of the codes for the sake of clarity, only kept what you coded). As the preprocessor replaces the #define directive with the text/value you provided thus you don't see the #define directives anymore after preprocessing. So it is clear what is going to be printed on the console/terminal.
As far as I know, the preprocessor uses #define statements in the order that it encounters them. In that case, your first printf statement correctly prints 3.14 and the second 3.141516 (is there a typo in the output from your program?).

Resources