6、C语言中的宏和预处理

6、C语言中的宏和预处理

在 C 语言编程中,所有以 # 开头的的内容都会被预处理器进行预处理,预处理器是一个特殊的程序,由编译器调用。编译器的目的就是将一个 C 语言程序转化为另一个不含任何 # 的 C 语言程序。

下面是一些有关 C 语言预处理器的有趣的事实:

  • 当我们使用 include 指令时,在预处理后,头文件中的内容将被复制到当前文件中,尖括号 <> 用于从标准头文件库中导入,而双引号 “” 用于从当前文件夹下导入头文件(一般尖括号用于导入系统级标准头文件,双引号多用于引入自定义头文件)

  • 当我们用 define 定义一个常量,预处理器将查找匹配给定的常量名称,并用给定的表达式进行替换,例如下面的程序中,max 被定义为 1000

    #include<stdio.h>
    #define max 100
    int main()
    {
      printf("max is %d", max);
    }
    // output: max is 100
    
  • 宏类似类似一个函数,这个函数的参数不需要检查数据类型,例如下面的宏定义 INCREMENT(x) 可以用于任意的数据类型。

    #include <stdio.h>
    #define INCREMENT(x) ++x
    int main()
    {
      char *ptr = "GeeksQuiz";
      int x = 10;
      printf("%s ", INCREMENT(ptr));
      printf("%d", INCREMENT(x));
      return 0;
    }
    //output: eeksQuiz 11
    
  • 宏参数在宏扩展之前没有被执行。例如,下面这段程序:

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

    上面的问题,可以通过下面的方式进行解决:

    #include <stdio.h> 
    //here, instead of writing a*a we write (a)*(b) 
    #define MULTIPLY(a, b) (a)*(b) 
    int main() 
    { 
        // The macro is expended as (2 + 3) * (3 + 5), as 5*8 
        printf("%d", MULTIPLY(2+3, 3+5)); 
        return 0; 
    } 
    //This code is contributed by Santanu 
    //output: 40
    
  • 通过宏定义的字符可以通过操作符 ## 串联起来,这个操作符称作 Token-Pasting 操作符。

    #include <stdio.h> 
    #define merge(a, b) a##b 
    int main() 
    { 
        printf("%d ", merge(12, 34)); 
    } 
    //output: 1234
    
  • 通过宏定义的参数可以在定义时候,前面加个 # ,可以将传入的参数转为字符串

    #include <stdio.h> 
    #define get(a) #a 
    int main() 
    { 
        // GeeksQuiz is changed to "GeeksQuiz" 
        printf("%s", get(GeeksQuiz)); 
    } 
    //output: GeeksQuiz
    
  • 宏定义可以通过 \ 写到多行中,最后一行不需要

    #include <stdio.h> 
    #define PRINT(i, limit) while (i < limit) \ 
                            { \ 
                                printf("GeeksQuiz "); \ 
                                i++; \ 
                            } 
    int main() 
    { 
        int i = 0; 
        PRINT(i, 3); 
        return 0; 
    } 
    //output: GeeksQuiz GeeksQuiz GeeksQuiz
    
  • 应避免使用带有参数的宏,因为它们有时会导致问题。这时候内联函数应该是首选的,因为在内联函数中有类型检查。从 C99 开始,C语言也支持内联函数。

    #include <stdio.h> 
      
    #define square(x) x*x 
    int main() 
    { 
        // Expanded as 36/6*6 
        int x = 36/square(6);  
        printf("%d", x); 
        return 0; 
    } 
    //output: 36
    

    如果我们使用内联函数,就会得到预期的输出。另外,上面第 4 点中给出的程序可以使用内联函数进行修正。

    #include <stdio.h> 
      
    static inline int square(int x) { return x*x; } 
    int main() 
    { 
    	int x = 36/square(6); 
    	printf("%d", x); 
    	return 0; 
    } 
    //output: 1
    
  • 预处理器还支持 if-else 语句,可直接用于条件选择

    int main() 
    { 
    #if VERBOSE >= 2 
      printf("Trace Message"); 
    #endif 
    } 
    # No Output
    
  • 一个头文件可能直接或间接的不止一次被引入,这会导致相同的变量/函数存在重定义的问题,为了避免这个问题,应该使用 defined, ifdefifndef

  • 有一些标准的宏定义可以用于输出程序文件目录(FILE)、编译日期(DATE)、编译时间(TIME)以及代码行数(LINE

    #include <stdio.h> 
      
    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 :9
    */
    
  • 移除已经定义的宏 undef MACRO_NAME

    #include <stdio.h> 
    #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

    #include <stdio.h> 
    #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; 
    } 
    //output: 1000 1001
    
  • 关于 undef 的另一个有趣的事实

#include <stdio.h> 
//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 
//output: 2.00 0.05
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值