Check The Programming Section
The #define creates two types of macros, as follows:
With parameter like function and
Without parameter
These macros are associations with an identifier or parameterized identifier with a token string. Once the macro is defined, the compiler can replace the macro identifier with its token string for each occurrence of the macro identifier in the source file. Syntax of the macro types are as follows:
#define identifier token-string
#define identifier(parameter list) token-string
The identifier is only replaced by the preprocessor when it forms a token. See the example given below:
#include<stdio.h>
#define A 20
#define B 30
int main(){
printf("%d",B);
}
In the given example, A and B are two maco identifiers and 20, 30 are the token string of A and B respectively. Inside the main method only B is appeared and before compilation of the code B will be replaced by its token string 30. Macro identifier is not replaceable, if it is part of some comment or long identifier name or any string. See the example given below:
#include<stdio.h>
#define A 20
#define B 30
int main(){
char name[] = "A it is a string";
/*It is A comment*/
int Aval;
}
In the above example, the macro identifier A appears as part of string ("A it is a string"), comment (/*It is A comment*/) and within a identifier name (Aval). For all of these macro expansion is not applicable.
The token-string can contains any of the followings given below:
Keyword
Constants or
Complete Statement
#include<stdio.h>
#define A int
#define B 30
#define C printf("Hello")
int main(){
A num1;
A num2;
printf("%d\n",B);
C;
}
In the above example, three #define preprocessor directives are declared with macro identifier name A, B and C. Keyword int is used as token-string with identifier A and constant 30 is used with macro identifier name B and a complete statement printf(“Hello”) is used as token-string with macro identifier C. Any white space is not part of any token-string. A #define without a token-string removes occurrences of identifier from the source file, without any error. See the example given below:
#include<stdio.h>
#define A
int main(){
A;
return 0;
}
The second syntax form defines a function-like macro with parameters. This form accepts an optional list of parameters that must appear in parentheses. After the macro is defined, each subsequent occurrence of identifier(s) is replaced with a version of the token-string argument that has actual arguments substituted for formal parameters. See the example given below:
#include<stdio.h>
#define print(A,B) printf("%d = %d + %d", A+B, A, B)
int main(){
int a = 20;
int b = 30;
print(a,b);
return 0;
}
In the above example, macro identifier print(A,B) have to parameters and the token-string printf(“%d = %d + %d”, A+B, A, B) uses two formal arguments mentioned in the macro identifier. Inside the source code when the macro identifier appears with actual arguments print(a,b) the values of the actual arguments are placed at the token-string in place of formal parameter A and B. Following points we need to taken care while working with the function like macros:
The number of parameters in the call must match the number of parameters in the macro definition.
Formal parameters need to be separated with comma.
Formal parameters can appear in any order and any number of times in the token-string.
Name of the formal parameter must be unique in the identifier.
There should not be any white-space in between the last character of the identifier name and the opening parentheses.
Arguments with side effects sometimes cause macros to produce unexpected results. A given formal parameter may appear more than one time in token-string. If that formal parameter is replaced by an expression with side effects, the expression, with its side effects, may be evaluated more than one time.
Many C program uses a macro min to get the minimum of two numbers as follows:
#define min(A,B) ((A)<(B)?(A):(B))
When we use macro with arguments containing side effects inside the source code, as follows:
int m = min(a+b, fun(c));
It expands as follows:
int m = ((a+b) < (fun(c)) ? (a+b): (fun(c)));
In the above example, a+b is expand for A and fun(c) for B. The function fun is used only once in the statement as it appears in the program, but the expression fun (c) has been substituted twice into the macro expansion. As a result, fun might be called two times when the statement is executed. If it has side effects or if it takes a long time to compute, the results might not be what you intended. We say that min is an unsafe macro.
To solve this problem we can use a GNU extension where fun(c) will be called once as follows:
#include <stdio.h>
#define min(A,B) \
({typeof (A) a_ = (A);\
typeof (B) b_ = (B);\
a_<b_ ? a_ :b_;})
int fun(int b){
return b+2;
}
int main()
{
int a = 34;
int b = 56;
printf("%d",min(a+b,fun(b)));
return 0;
}
The ‘({ … })’ notation produces a compound statement that acts as an expression. Its value is the value of its last statement. This permits us to define local variables and assign each argument to one. The local variables have underscores after their names to reduce the risk of conflict with an identifier of wider scope (it is impossible to avoid this entirely). Now each argument is evaluated exactly once.
If we not have GNU extension then the only solution is to be careful when using the macro min. For example, we can calculate the value of fun (c), save it in a variable, and use that variable in min:
#include <stdio.h>
#define min(A,B) ((A)<(B)?(A):(B))
int fun(int b){
return b+2;
}
int main()
{
int a = 34;
int b = 56;
int c = fun(b);
printf("%d",min(a+b,c));
return 0;
}