Difference between Call-by-name and Call-by-macro-expansion - c

Let's assume we have the following code in a language that looks a lot like C.
int A[2];
A[0]=4;
A[1]=7;
void f(int x, int y) {
x++; A[1]++; y++;
printf(x, y, A[0], A[1]);
}
void main() {
int k = 0;
f(k, A[k]);
print(k, A[0], A[1]);
}
I want to define the output of this program.
I haven't understood well the difference between the call-by-name and the call-by-macro-expansion method.
So, in the call-by-name method, k is initialized to 0 and then f() function is called. x becomes equal to "k" and y becomes equal to "A[k]". The first command in the called function is x++ which increases the value of "k" by 1. So k becomes equal to 1. Then A[1] is increased, so A[1] becomes 7+1=8. None of the x,y are affected. Finally, we have the command y++ which increases the value of "A[k]" by 1, so it increases the value of A[1] (since now k=1) by 1, so A[1] becomes now 8+1=9.
Then f() prints: 1,9,4,9
And then we return to the main() fuction which prints: 1,4,9
So, the output of the program is 1,9,4,9,1,4,9 if I am not mistaken.
But how does call-by-macro-expansion differs from this method? What does it change?

There is nothing like "call-by-macro" in C language. There are only macros which take parameters. Macros are just textually replaced by the preprocessed tokens.
IMO macros should be used only if they are really needed, in most cases it better to use inline functions. Macros are dificult to debus (as compiler compiles the preprocessed .c file) and error prone.
Example
#define SUB(a,b) a-b
and the usage
printf("%d", SUB(3-2,4-5));
the result will not be 2 only -8

But how does call-by-macro-expansion differs from this method? What does it change?
For C, "call-by-macro-expansion" doesn't exist. Instead, for macros the preprocessor does a glorified "cut&paste" operation on raw text.
For example, if you have this:
int A[2];
A[0]=4;
A[1]=7;
#define MACRO(x, y) { \
x++; A[1]++; y++; \
printf(x, y, A[0], A[1]); \
}
void main() {
int k = 0;
MACRO(k, A[k]);
print(k, A[0], A[1]);
}
Then the preprocessor will cut&paste the text from the macro to where the macro is used and then replace x and y with the arguments you provided, so that (after preprocessing) the source code looks like this:
int A[2];
A[0]=4;
A[1]=7;
void main() {
int k = 0;
{ \
k++; A[1]++; A[k]++; \
printf(k, A[k], A[0], A[1]); \
}
print(k, A[0], A[1]);
}
Of course the macros don't need to contain valid code, and the source doesn't even need to be C at all (e.g. you could use the preprocessor to preprocess assembly language source code by telling the compiler "don't compile, just output the preprocessed text"); and there's no real reason why you can't use a completely different preprocessor (with completely different features and/or macro syntax) and feed the resulting text into a C compiler (telling the compiler "don't preprocesses, just compile").
In practice; the main differences for macros and functions are:
for macros, there's no type-checking on the parameters, so bugs end up being more annoying to find
for macros, a debugger will only say the line number where the macro was expanded and won't say where the code actually came from, so bugs end up being more annoying to find
for macros, because they don't have to be valid C you can do some bizarre shenanigans (e.g. #define forever while(1) { so you can use forever i++; } as an infinite loop), and can be powerful for code obfuscation (deliberately making it hard to read the code).
for functions, the compiler can decide not to inline the function to reduce code size
for functions, you can have recursion (with macros you can't - it'd end up being an infinite amount of text)
for functions, you can have function pointers and/or have external functions (where the linker figures out where the function is, either with static linking or dynamic linking).
For a simpler example of (a) difference, consider this code:
#define f(x) { \
x++; \
}
void g(int x) {
x++;
}
void main() {
int a = 1;
int b = 1;
f(a);
printf("%d\n", a);
g(b);
printf("%d\n", b);
}
These look the same, but are not. After expanding the macro and inlining the function, it becomes more like this:
void main() {
int a = 1;
int b = 1;
a++;
printf("%d\n", a); // Will print "2' because the original `a` was changed
int x = b;
x++;
printf("%d\n", b); // Will print "1' because the original `b` was not changed
}
Note that this is exactly the same problem with the example above (for the macro, the x++; modifies the original k and not a copy of the original k; and for the function the x++; modifies a copy and not the original).

Related

How does macro function in c uses the pass by reference

I' m learning Macro in c,
I wrote a small function in macro to swap number, but passed the value as 'pass by value' since i didn't use address of operator (&) before the variable in the argument, But when i ran the program. The value got swaped. You can refer the code and mention me where i got wrong in understanding?
#include<stdio.h>
#include<conio.h>
#define swap(a,b) a = a+b;b = a-b; a = a-b;
int main()
{
int x = 5, y = 10;
swap(x,y);
printf("%d %d\n",x,y);
getch();
return 0;
}
Do the arguments acts as pass by reference, when using it in macro?
C doesn't have pass-by-reference. And that's not what's happening here anyway. When a macro is "called", the preprocessor replaces the call-site with the body.
With your example, the invocation
swap(x,y);
is replaced by
x = x+y;y = x-y; x = x-y;;
This last line is what the actual parser of the compiler sees.
Many compilers have options to stop after the preprocessing step. I suggest you use that to see exactly what the preprocessor have done.
I also hope you start to see how macros can "break" your code.
For example if the code was
if (some_condition)
swap(x,y);
Then it would be expanded to (with some reformatting)
if (some_condition)
x = x+y;
y = x-y;
x = x-y;
;
This is clearly not what was intended and will not work.
You also have the case when the arguments to the macro are not simple variables, but expressions. Like
swap(x+1,y*2)
While would be replaced by
x+1 = x+1+y*2;y*2 = x+1-y*2; x+1 = x+1-y*2;;
This also would not work.

Ununderstandable function-like macro in C

i have this c macro code :
#define d(x, y, z) ( \
x += z, \
y += x, \
x += y \
)
I have several questions :
Does this macro function return something ? (e.g. return x, y, or z)
or is it just add the parameter variable with itself ? (which is
useless, i think).
What does the \ means ?
Why does the original coder use comma-operator after each operation ? Why not just use ; instead of , ?
Any help would be appreciated
Does this macro function return something ? (e.g. return x, y, or z) or is it just add the parameter variable with itself ? (which is useless, i think).
It modifies the value of the variables. The "return" value is the final value of x.
What does the \ means ?
When placed last on a line, it negates the newline so that the macro definition can span more than one line.
Why does the original coder use comma-operator after each operation? Why not just use ; instead of `, ?
Macros replace text. Consider the following code:
int x=1, y=2, z=3, f;
f = 3 * (d(x,y,z));
If the macro uses comma, the code becomes:
int x=1, y=2, z=3, f;
f = 3 * (x+=z, y+=x, x+=y); // Evaluates to 3 * (the final value of x)
If the macro uses semicolon, the code becomes:
int x=1, y=2, z=3, f;
f = 3 * (x+=z; y+=x; x+=y); // Syntax error!!!
1) The macro does not return anything itself. It is just a dumb piece of code substituted literally by the preprocessor wherever it encounters it. It can be any kind of text.
2) \ is used for letting the preprocessor know that the current macro also expands over the next line. (multi-line macro)
3) I cannot make any assumption about the original coder's intentions. However by using the comma operator in there the whole macro becomes a C language expression. For example running something like this works (it wouldn't if semicolons were in there):
int a = 0;
int x = 1;
int y = 2;
int z = 3;
a = d(x, y, z);
printf("a = %d\n", a);
printf("x = %d\n", x);
printf("y = %d\n", y);
printf("z = %d\n", z);
and prints:
a = 10
x = 10
y = 6
z = 3
First and foremost #define is a Preprocessor Directive, which means when the source code/c code is complied the #define replaces LHS with RHS - meaning whereever the d(x,y,z) is used will be replaced with the equation given
for example the below c code will print - modified a = 9, b=8, c=9
#define d(x,y,z) \
x+=1, \
y+=2, \
z+=3
#include <stdio.h>
int main()
{
unsigned int a,b,c;
a=5;
b=6;
c=7;
printf("modified a = %d, b=%d, c=%d \n",d(a,b,c));
}
basically what happened here is d(a,b,c) - is replaced with a+=1,b+=2,c+=3
The meaning of \ is that the pre-processor directive continues in the next line.
As for as the comma-operator is concerned we need to look at source code to see where exactly it is used. as you can see in the above code the comma operator actually separates all the three variables and is able to print properly - if in case i replace comma with any other operator we will get compilation error.
Hope this answers your questions :)
Regards
Hari

Passing parameters evaluation direction in macro

As I know in C, passing of actual parameters of a function evaluation starts from rightmost and directed to left.
What is the case for a macro definition with parameter? I made a code to make the sense clear but output confused me...
Here is the code.,
#define parsing(a,b) a*b
int parsefun(int a, int b)
{
return a*b;
}
int main()
{
int i=10;
printf("%d\n",parsing((i++),i));
i=10;
printf("%d\n",parsing(i,(i++)));
i=10;
printf("%d\n",parsefun((i++),i));
i=10;
printf("%d\n",parsefun(i,(i++)));
system("PAUSE");
return 0;
}
This code outputs,
100
100
100
110
I hoped same output for macros as function. But where is the crucial point here?
parsing of actual parameters of a function starts from rightmost and directed to left
I think you mean "evaluation" rather than "parsing". But that's not true, the C standard does not specify an order.
So the behaviour you're getting for the functions is unspecified by the C standard.
I hoped same output for macros as function
Macro arguments are not evaluated, they're simply substituted. So you end up with this:
int i=10;
printf("%d\n", (i++) * i);
i=10;
printf("%d\n", i * (i++));
After which, you're simply seeing undefined behaviour, as explained in this question: Why are these constructs (using ++) undefined behavior?.

How can I define, in the C programming language, a FIRST macro that let's me declare scoped variables?

I have the following macros
#define FIRST(first) \
switch(first, 0) default:
#define LAST(last) \
switch(0) for(;0;last) default:
#define BRACKET(first, last) \
switch(first, 0) for(;0;last) default:
And they are used like so.
#include <stdio.h>
// ... Macros are defined here
int main (int argc, const char * argv[])
{
int x;
FIRST(x = 4)
{
printf("%i\n", x);
}
LAST(++x)
{
printf("%i\n", x);
}
printf("%i\n", x);
return 0;
}
BRACKET is simply a combination of FIRST and LAST. The FIRST macro, (and the BRACKET macro), isn't good enough though. I'd like to be able to write the following code where y is scoped to the curly braces.
FIRST(int y = 0)
{
printf("%i\n", y);
}
How can I write a FIRST macro, in the C programming language that lets me declare a variable scoped within the curly braces?
Some corner cases are:
I want the following code snippet allowed
FIRST(int x = 0)
printf("%i\n", x);
I want the folllowing code snippet disallowed
FIRST(int x = 0)
printf("%i\n", x);
++x;
printf("%i\n", x);
P.S. I'm surprised that "switch(0) for(;0;last) default:" is accepted by the compiler, is this really legal C code?
To obtain scoped variables in the way you want is easy if you have a compiler that is at least complying to C99. (otherwise don't do it, or get yourself a modern compiler).
A prefix to a block or statement like FIRST(int y = 0) can be realized by something like
for (int t = 0; t < 1; ++t)
for(int y = 0; t < 1; ++t)
that is you define an auxiliary variable that controls the loop to be executed exactly once. Modern compilers easily optimize the noise that comes with this and go to the essential.
With some care you can pack that into a macro, where you should take care that the name also captures what is going on and that you don't hurt the eyes of your fellow programmers. In particular put a big warning label somewhere that such things change the semantic of break and continue statements to something quite surprising for the unaware reader.
I have written up more on scope bound resource management with for-scopes.

How to concatenate two or more Integers using Macros?

If a=1, b=2, c=3... I would like to write a macro which concatenates them like this 123.
But when I try this:
#include<stdio.h>
#define cat(a,b,c) a##b##c
int main()
{
int a=1,b=2,c=3,d;
d=cat(1,2,3); //Works
d=cat(a,b,c); // Returns an error...How to make this work?
return 0;
}
You can't -- the preprocessor has no idea about variables and what values you're going to assign to them when the program runs at some arbitrary time after the preprocessor has finished executing.
hash-define macros are pre-compile time and are preprocessed before compilation. The preprocessor will not have access to variable values. d=cat(a,b,c) will get converted to d=abc by the preprocessor.
You would need to use itoa or something similar and concatenate the resulting strings and then atoi back.
Or just do some arithmetic to figure out the result.
Preprocessor stringifying can't work on variables, it has to take a literal and convert it to a string during processing; the preprocessor deosn't know what a, b, and c equals in your cat() call. You would need to write a macro that actually uses C++ to do the combining. For example:
#define cat(a, b, c, d) \
do { \
std::stringstream ss; \
ss << a << b << c; \
ss >> d; \
} while(0)
(the do/while(0) is a common hack to let you add a semi-colon after the cat call safely)
You won't be able to use a "return value" from this, but you can do:
int a = 1, b = 2, c = 3, d;
cat(a, b, c, d);
// d == 123 now
This might be a starting point:
#include <stdio.h>
#define cat(x,a,b,c) snprintf(x, sizeof(x), "%d%d%d", a, b, c)
main(int argc, char *argv[])
{
char s[20];
cat(s, 4,5,6);
printf("%s\n", s);
}
if it it isnt important that this is done at compile time, you can use something like this:
#include <math.h>
unsigned intcat(unsigned a, unsigned b, unsigned c)
{
unsigned dlogc = 1 + (unsigned)(log(c)/log(10));
unsigned dlogb = 1 + (unsigned)(log(b)/log(10));
return (unsigned)(c + pow(10,dlogc) * b + pow(10,dlogb+dlogc) * a);
}
i dont know if there is anything in the boost libraries to do such math at compile time using TMP.
It is possible for preprocessor defined integers.
The preprocessor needs a call to another function to expand.
You do it as follows:
#define I_BASE_CONCAT(x,y) x ## y
#define I_CONCAT(x,y) I_BASE_CONCAT(x,y)
There it is. Now if you call I_CONCAT it will expand it to x##y, but with the values of x and y.
The C preprocessor does just dummy text substitution at compile time.
What means text substitution? The preprocessor will output C code substituting the parameters of the macro with the passed values. It does not matter if you pass a variable or a constant number, you will just get dummy substitution (also called macro "expansion").
Let's go to see how the preprocessor will "expand" #define cat(a,b,c) a##b##c.
d=cat(1,2,3); expands to: d=123; and this is valid code because you have declared int d.
d=cat(a,b,c); expands to: d=abc; and this will not compile since there's no int abc variable.
What means compile time? It means that this text substitution is done on the source code, and the output disregards the content of the variables passed to the macro. In other words, it does not matters that you have initialized a, b, and c to 1, 2, and 3: the result will be just the concatenation (due to the ## "token-pasting" preprocessor operator) of the passed values. In your case the result is abc, which means nothing in your code.
You could also use this function to concatenate 3 integers
(the other intcat function above does not work when a 0 is the second or third digit. That is because the log of 0 is negative infinity and when you pass 0 it subtracts 1 from your total).
unsigned intcat(unsigned a, unsigned b, unsigned c)
{
uint8_t ax = a;
uint8_t bx = b;
uint8_t cx = c;
ax = (ax * 100);
bx = (bx * 10);
cx = (cx * 1);
return(ax + bx + cx);
}

Resources