C Preprocessor

1.
#include <stdio.h>
#define print(x) printf("%d", x)
int x; 
void P(int *y)
{
    int x = *y+2;
    *y=x-1;
    print(x);
}
int main(void)
{
    x=5;
    P(&x);
    print(x);
}

What is the output of the program given above?

Output : 76

2. Write a macro to find larger of two numbers

#define LARGER(a,b) ((a)>(b)?(a):(b))
3. Consider the statement
double ans = 18.0/square(2+1)
For the following #define macros, write what will be the value of ans.
#define square(x) x*x
#define square(x) (x)*(x)
#define square(x) (x*x)
#define square(x) ((x)*(x))
  • First one becomes 18.0/2+1/2+1 = 10
  • Second macro will be expanded as 18.0/(2+1)*(2+1) = 18/3*3 = 18
  • Third macro expands to 18.0/(2+1*2+1) = 18.0/5 = 3.6
  • Fourth macro is expanded as 18.0/((2+1)*(2+1)) = 18.0/9 = 2.0

So only fourth macro is correctly defined.

Because such unforeseen errors which are not caught by compiler, but produce wrong results, it is a good practice to avoid preprocessor macros as much as possible.

4. What is the difference between #include< > and #include" "

If include file name is specified in angle brackets - <>, the file is searched in standard include directory of C compiler first.

If the include file is specified in double quotes, it is searched in current directory first, if not found, it is then searched in standard include directories as well.

If the include filename is given with complete path, then it is searched only in that path.

This the reason, include macro for stdio.h and other library header files are written in angle brackets.

When you are including standard header files, you should enclose the file name in angle brackets. If you are including a header file specific to your program, you should enclose the file name in double quotes.

5. What will be the output of the following program
#include<stdio.h>
#define square(x) x*x
int main()
{
   int n=10;
   int m=5;
   n = n+square(m+2);
   printf("%d",n);
}

17

The macro square(x) will be expanded as

m+2*m+2

As multiplication operator has a higher precedence than addition operator, this will be m+2m+2 = 17. Which is a wrong answer.

6. What will be the output of this program
#include<stdio.h>
#define PRINT(s1, s2) printf("%s=%d %s=%d \n", #s1, s1, #s2, s2);
int main()
{
    int n1=4;
    int n2=5;
    PRINT(n1,n2);
    return 0;
}

n1=4 n2=5

When # is used along with a parameter in macro definition, it stringifies the argument. That is, it adds double quotes to the argument and converts it to a string.

#s1 and #s2 use stringify operator.

The macro converts the PRINT(n1,n2) to

printf("%s=%d %s=%d\n","n1",n1,"n2",n2);
7. What is conditional compilation in C?

Using #if of #ifdef or #ifndef macros, the preprocessor can include or exclude part of the code. This is called conditional compilation.

It is used for compiling for different architectures or different standards etc.

e.g.

#include<stdio.h>
#define m 10  
int main()  
{
      printf("Hello world\n");  
 #ifdef m     
      printf("Good bye world\n");  
#endif  
}

Output will be
Hello world
Good bye world

But if "#define m 10" is removed from program, printf("Good bye world\n") omitted from the program by preprocessor. And output will be just
Hello world

Consider another example of conditional compilation.

sum = 0;
for(i=0;i<10;i++)
{
    int sq = i*i;
#ifdef DEBUG
    printf("%d is %d\n",i,sq);
#endif
   sum +=sq;
   }

Here for debugging, you need to define macro DEBUG. And the compiler includes printf statement in the loop. If you don't define DEBUG then printf is not included in the for loop

8. What are the differences between #define and typedef?

#define is just preprocessor macro and is error prone. It just literally replaces one text with another. Where as typedef gives a new name to a type.

Consider this example

#define INTPTR int *
   typedef int * INTPTR2;
   int main()
   {
        INTPTR p1,p2;
        INTPTR2 p3,p4;
        }

line 1 in main() will be preprocessed as

int *p1,p2;

So p2 will be an integer instead of integet pointer.

But p3 and p4 will be integer pointers becaue typedef is defining INTPTR2 as int *

typedef can be used to simplify definition of complex data types.

e.g.

typedef int *INTPTR;
        typedef INTPTR (*FPTR)(INTPTR);

Here, FPTR is function pointer which takes an integer pointer as a paramter and also returns an integer pointer.

9. Can a macro be redefined? If yes, how?

Macro can be redefined after undefining it using #undef

e.g.

#define NUM 10
#undef NUM 
#define NUM 5

10. What is the output of this program?
#include<stdio.h>
int main()
{
    printf("%s\n",__DATE__);
    printf("%s",__FILE__);
}

It prints the system date and in the next line it prints the filename of the current C program.

__FILE__, __DATE__, __TIME__ are all predefined macros.

__FILE__ gives a string which is file name with full path

__DATE__ gives system date at the time of compilation

__TIME__ gives system time at the time of compilation

11. Write a macro to print the name and value of an integer.

#define PRINT(x) printf("%s = %d\n",#x,x)

#operator used with a parameter in a macro definition converts the parameter into a double quoted string.

12. How do you define a constant in C? How is a constant better than a macro?

To define a constant, we use constant name, type, value and const keyword.

e.g.

   const int a = 10;

Once defined, value of a constant can not be changed.

A macro is error prone because compiler does not see the macro - it only sees the expansion. So it is always preferrable to use a constant (using const keyword) instead of a macro.

13. Write a program to print the same file on console.

#include<stdio.h> 
int main()
{
    char *filename = __FILE__;
    FILE *fptr = fopen(filename,"r");
    int c;
    while((c=fgetc(fptr))!=EOF)
          putchar(c);
    fclose(fptr);
    return 0;
}