📜  关于C语言中的宏和预处理器的有趣事实

📅  最后修改于: 2021-05-26 01:25:41             🧑  作者: Mango

在C程序中,以开头的所有行均由预处理器处理,预处理器是由编译器调用的特殊程序。这样,我们的意思是说“#”符号用于处理程序中的其他语句之前的功能,也就是说,这意味着它在运行时之前或在编译时处理某些代码。用最基本的术语来说,预处理器采用一个C程序并生成另一个没有任何#的C程序。

以下是有关C中预处理器的一些有趣事实。

1)当我们使用include指令时,包含的头文件(经过预处理)的内容被复制到当前文件中。
尖括号<>指示预处理器在保存所有头文件的标准文件夹中查找。用双引号指示预处理器查看当前文件夹(当前目录)。

2)当我们使用define作为常量时,预处理器会生成一个C程序,在该程序中搜索定义的常量,并用给定的表达式替换匹配的标记。例如,在下面的程序中, max定义为100。

C
#include
#define max 100
int main()
{
    printf("max is %d", max);
    return 0;
}


C
#include 
#define INCREMENT(x) ++x
int main()
{
    char *ptr = "GeeksQuiz";
    int x = 10;
    printf("%s  ", INCREMENT(ptr));
    printf("%d", INCREMENT(x));
    return 0;
}


C
#include 
#define MULTIPLY(a, b) a*b
int main()
{
    // The macro is expanded as 2 + 3 * 3 + 5, not as 5*8
    printf("%d", MULTIPLY(2+3, 3+5));
    return 0;
}
// Output: 16


C
#include 
//here, instead of writing a*a we write (a)*(b)
#define MULTIPLY(a, b) (a)*(b)
int main()
{
    // The macro is expanded as (2 + 3) * (3 + 5), as 5*8
    printf("%d", MULTIPLY(2+3, 3+5));
    return 0;
}
// This code is contributed by Santanu


C
#include 
#define merge(a, b) a##b
int main()
{
    printf("%d ", merge(12, 34));
}


C
#include 
#define get(a) #a
int main()
{
    // GeeksQuiz is changed to "GeeksQuiz"
    printf("%s", get(GeeksQuiz));
}


C
#include 
#define PRINT(i, limit) while (i < limit) \
                        { \
                            printf("GeeksQuiz "); \
                            i++; \
                        }
int main()
{
    int i = 0;
    PRINT(i, 3);
    return 0;
}


C
#include 
 
#define square(x) x*x
int main()
{
    // Expanded as 36/6*6
    int x = 36/square(6);
    printf("%d", x);
    return 0;
}


C
#include 
 
static inline int square(int x) { return x*x; }
int main()
{
int x = 36/square(6);
printf("%d", x);
return 0;
}


C
int main()
{
#if VERBOSE >= 2
  printf("Trace Message");
#endif
}


C
#include 
 
int main()
{
   printf("Current File :%s\n", __FILE__ );
   printf("Current Date :%s\n", __DATE__ );
   printf("Current Time :%s\n", __TIME__ );
   printf("Line Number :%d\n", __LINE__ );
   return 0;
}


C
#include 
#define LIMIT 100
int main()
{
   printf("%d",LIMIT);
   //removing defined macro LIMIT
   #undef LIMIT
   //Next line causes error as LIMIT is not defined
   printf("%d",LIMIT);
   return 0;
}
//This code is contributed by Santanu


C
#include 
#define LIMIT 1000
int main()
{
   printf("%d",LIMIT);
   //removing defined macro LIMIT
   #undef LIMIT
   //Declare LIMIT as integer again
   int LIMIT=1001;
   printf("\n%d",LIMIT);
   return 0;
}


C
#include 
//div function prototype
float div(float, float);
#define div(x, y) x/y
 
int main()
{
//use of macro div
//Note: %0.2f for taking two decimal value after point
printf("%0.2f",div(10.0,5.0));
//removing defined macro div
#undef div
//function div is called as macro definition is removed
printf("\n%0.2f",div(10.0,5.0));
return 0;
}
 
//div function definition
float div(float x, float y){
return y/x;
}
//This code is contributed by Santanu


输出:
max is 100

3)宏可以采用类似参数的函数,不检查参数的数据类型。例如,下面的宏INCREMENT(x)可以用于任何数据类型的x。

C

#include 
#define INCREMENT(x) ++x
int main()
{
    char *ptr = "GeeksQuiz";
    int x = 10;
    printf("%s  ", INCREMENT(ptr));
    printf("%d", INCREMENT(x));
    return 0;
}
输出:
eeksQuiz  11

4)宏扩展之前不评估宏参数。例如,考虑以下程序

C

#include 
#define MULTIPLY(a, b) a*b
int main()
{
    // The macro is expanded as 2 + 3 * 3 + 5, not as 5*8
    printf("%d", MULTIPLY(2+3, 3+5));
    return 0;
}
// Output: 16
输出:
16

可以使用以下程序解决先前的问题

C

#include 
//here, instead of writing a*a we write (a)*(b)
#define MULTIPLY(a, b) (a)*(b)
int main()
{
    // The macro is expanded as (2 + 3) * (3 + 5), as 5*8
    printf("%d", MULTIPLY(2+3, 3+5));
    return 0;
}
// This code is contributed by Santanu
输出:
40

5)传递给宏的令牌可以使用称为令牌粘贴运算符运算符##进行级联。

C

#include 
#define merge(a, b) a##b
int main()
{
    printf("%d ", merge(12, 34));
}
输出:

1234

6)传递给宏的令牌可以通过在其前面使用#转换为字符串字面量。

C

#include 
#define get(a) #a
int main()
{
    // GeeksQuiz is changed to "GeeksQuiz"
    printf("%s", get(GeeksQuiz));
}
输出:
GeeksQuiz

7)宏可以使用’\’写入多行。最后一行不需要带有“ \”。

C

#include 
#define PRINT(i, limit) while (i < limit) \
                        { \
                            printf("GeeksQuiz "); \
                            i++; \
                        }
int main()
{
    int i = 0;
    PRINT(i, 3);
    return 0;
}
输出:
GeeksQuiz GeeksQuiz GeeksQuiz

8)应避免使用带有参数的宏,因为它们有时会引起问题。并且应该首选内联函数,因为内联函数中有类型检查参数评估。从C99开始,C语言也支持内联函数。

例如,考虑以下程序。乍一看,输出似乎为1,但输出为36。

C

#include 
 
#define square(x) x*x
int main()
{
    // Expanded as 36/6*6
    int x = 36/square(6);
    printf("%d", x);
    return 0;
}
输出:
36

如果使用内联函数,则将获得预期的输出。同样,可以使用内联函数来更正上面第4点中给出的程序。

C

#include 
 
static inline int square(int x) { return x*x; }
int main()
{
int x = 36/square(6);
printf("%d", x);
return 0;
}
输出:
1

9)预处理器还支持if-else指令,这些指令通常用于条件编译。

C

int main()
{
#if VERBOSE >= 2
  printf("Trace Message");
#endif
}
输出:
No Output

10)头文件可能被多次直接或间接包含,这导致重新声明相同变量/函数的问题。为了避免这个问题,指示等规定,IFDEFIFNDEF使用。

11)有一些标准宏可用于打印程序文件(__FILE__),编译日期(__DATE__),编译时间(__TIME__)和C代码中的行号(__LINE__)

C

#include 
 
int main()
{
   printf("Current File :%s\n", __FILE__ );
   printf("Current Date :%s\n", __DATE__ );
   printf("Current Time :%s\n", __TIME__ );
   printf("Line Number :%d\n", __LINE__ );
   return 0;
}
输出:
Current File :/usr/share/IDE_PROGRAMS/C/other/081c548d50135ed88cfa0296159b05ca/081c548d50135ed88cfa0296159b05ca.c
Current Date :Sep  4 2019
Current Time :10:17:43
Line Number :8

12)我们可以使用删除已经定义的宏:
#undef MACRO_NAME

C

#include 
#define LIMIT 100
int main()
{
   printf("%d",LIMIT);
   //removing defined macro LIMIT
   #undef LIMIT
   //Next line causes error as LIMIT is not defined
   printf("%d",LIMIT);
   return 0;
}
//This code is contributed by Santanu

删除先前定义的宏LIMIT后,我们已将LIMIT声明为整数变量,因此以下程序已正确执行

C

#include 
#define LIMIT 1000
int main()
{
   printf("%d",LIMIT);
   //removing defined macro LIMIT
   #undef LIMIT
   //Declare LIMIT as integer again
   int LIMIT=1001;
   printf("\n%d",LIMIT);
   return 0;
}
输出:
1000
1001

关于使用( #undef )宏的另一个有趣的事实

C

#include 
//div function prototype
float div(float, float);
#define div(x, y) x/y
 
int main()
{
//use of macro div
//Note: %0.2f for taking two decimal value after point
printf("%0.2f",div(10.0,5.0));
//removing defined macro div
#undef div
//function div is called as macro definition is removed
printf("\n%0.2f",div(10.0,5.0));
return 0;
}
 
//div function definition
float div(float x, float y){
return y/x;
}
//This code is contributed by Santanu
输出:
2.00
0.50
想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。