• C语言预处理_05


    凡是以 “#”开头的均为预处理命令!

    其定义的一般形式为:

       #define  标示符  字符串

    对于宏定义说明以下几点:

    1.宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现!

    2.宏定义不是说明或语句,在行末不需要加上分号,若加上分号则连分号一起置换。

    3.宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可以使用 “#undef”命令。

    4.宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。

    5.宏定义允许嵌套,在宏定义的字符串中可以使用定义的宏名。在宏展开时由预处理程序层层代换

    6.习惯上宏名用大写字母表示,以便于与变量区别!

    7.可用宏定义表示数据类型,是书写方便。 例如 #define INTEGER int

    #define 与 typedef 的区别:宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标示符具有类型定义说明的功能。typedef 后面会有分号,表示语句的结束。

    一、无参数的宏定义

    下面一段小程序,说明 #define 与 typedef 的区别:

     1 #define PIN1 char* // 宏定义
     2 typedef char* PIN2; // 重类型说明符重新命名
     3 
     4 int main(void) {
     5     PIN1 x, y;
     6     PIN2 a, b;
     7     printf("By #define : %lu %lu
    
    ", sizeof(x), sizeof(y));
     8     printf("By typedef : %lu %lu
    
    ", sizeof(a), sizeof(b));
     9     // 替换之后
    10     /*
    11      char *x, y;  // x为一个指针, y是一个字符型
    12      char *x, *y; // x, y均为指针类型
    13      */
    14     return 0;
    15 }

    打印结果:

    1 By #define : 8 1 // 在我当前环境,指针类型占8个字节,char字符站1个字节
    2 
    3 By typedef : 8 8 // x, y均为指针类型

    编程中,适当使用宏定义可以提升我们的开发效率,但是慎用!

    不用循环和递归,实现打印0-999:

    1 #define BD(x) x;x;x;x;x;x;x;x;x;x;
    2 int main(void) {
    3     int n = 0;
    4     BD(BD(BD(printf("%d
    ", n++))));
    5 }

    二、带参数的宏定义

    C语言允许宏有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。

    对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

    带参宏定义的一般形式: #define  宏名(形参表)  字符串

    对于带参数的宏定义有以下问题需要注意:

    1.带参数的宏定义,宏名和参数表之间不能有空格出现

    例如:

    1 #define MAX(a,b)  ((a > b) ? a : b)  // 正确写法
    2 #define MAX (a,b)  ((a > b) ? a : b) // 错误写法

    2.在带参数宏定义中,形式参数不分配内存单元,因为不必作类型定义。而宏调用中的实参有具体的值。要用他们去代换形参,因此必须作类型说明符。

    3.在宏定义中的形参是标示符,而宏调用中的实参可以使表达式。

    4.在宏定义中,字符串中的形参通常要用括号括起来以避免出错。

    1 #define PT(x) (x) * (x)
    2 #define BT(x) x * x
    3 int main(void) {
    4     printf("PT=%d
    BT=%d
    ", PT(3 + 1), BT(3 + 1));
    5 }

    5.带参数的宏和带参数的函数相似。但本质上不同!!

    条件编译

    预处理程序提供了条件编译的功能。可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。这对于程序的移植和调试时很有用的。不建议是用 /**/ ,因为C语言中不可以多行注释嵌套多行注释。建议使用预处理条件编译注释。

    示例:

    1 int main(void) {
    2 #if 0
    3     printf("-----------"); // 此处肯定不会执行
    4 #endif
    5     printf("Learning and record
    ");
    6 }


    条件编译有三种潜规则:

    第一种形式:

    #ifdef 标示符
        程序段1
    #else
        程序段2
    #endif

    或:

    #ifdef 标示符
        程序段2
    #endif

    功能:如果标示符已被 #define 命令定义过则对"程序段1"进行编译;否则对"程序段2"进行编译

    第二种形式:

    #ifndef 标示符
        程序段1
    #else
        程序段2
    #endif

    功能:如果标示符没有被 #define 命令定义过则执行"程序段1";否则执行"程序段2"

    场景:如果没有定义“标示符”,我们可以在“程序段1”位置定义“标示符”,以确保这个标示符的存在。

    示例:

    int main(void) {
        // 若该宏未定义
    #ifndef STRING
        // 则给予定义
        #define STRING "Learning and record……
    "
    #endif
        // 方便我们使用
        printf("---%s", STRING);
    }

    第三种形式:

    #if 常量表达式
        程序段1
    #else
        程序段2
    #endif

    功能:如果“常量表达式”为真,则执行“程序段1”,反之执行“程序段2”

    尊重作者劳动成果,转载请注明: 【kingdev】

  • 相关阅读:
    最常被程序员们谎称读过的计算机书籍
    天气城市代码,市级城市. 用java的map.中国天气网.
    你所知道的学习方法,都是错的!
    解决「问题」,不要解决问题
    [IOS 下重温设计模式] AbstractFactory
    判断UIView是否装载完成
    va_start、va_end、va_list的使用
    [IOS 下重温设计模式] Singleton
    IOS BLOCK收集
    SEL
  • 原文地址:https://www.cnblogs.com/xiu619544553/p/5310813.html
Copyright © 2020-2023  润新知