7.1 宏定义

文件包含指令

        #include

                1.将所包含文件的内容粘贴到该指令处

                2.尖括号包含:#include

                        先到 -l 目录找,再找系统目录( /usr/inlcude )

                        适用于系统文件

                3.双引号包含:#include "xxx.h"

                        先到 -l 目录,再找当前目录,最后找系统目录

                        适用于自己编写的头文件

                        命令预处理: gcc -E -o xxx.i xxx,c

                        使用后,会将头文件中的内容全部放入预处理文件中

宏定义指令

        #define分类:

                无参宏定义(常量宏)

                        #define 宏名 (宏值)

                        例如:#define PI 3.14 将PI始终赋值3.14

                                当 printf("%lg\n",3.14*r*r); 可以替换为printf("lg\n",PI*r*r);

                                        当需求更精密的圆周率时只需修改宏即可

                        1.宏替换只是简单的文本替换,编辑器对所替换的内容不做任何检查,更不会计算表达式或者调用函数

                        2.如有错误,只能在编译时发现

                        3.行末不必加分号,若加上分号连分号一起做宏替换

                        4.宏定义必须写在所有函数之外,其作用域从宏定义指令开始一直到源程序结束

                        5.宏名在源程序中若用引号括起来,则预处理器不对其做宏替换

                        6.在宏定义的字符串中可以使用已定义过的宏名

                        7.宏名习惯用大写字母表示,以区别于变量和函数,但也允许小写字母

                        8.定义常量,便于修改

                        9.定义类型,简化书写

                                用typedef定义类型别名效果更好

                        10.定义模式,语言扩展

                                不要滥用

                有参宏定义

                        #define 分类 即宏函数

                        有参宏定义 (宏参数)

                        #define 宏名(参数表) (宏参)

                        例如: #define SQUARE(X) ((X)*(X)) 只做替换,不做运算

                                #define SQUARE_1(X) (X*X) //定义宏函数求一个数的平方

                                printf("%d\n", SQUARE_1(3+7));//3+7*3+7

                                这里就和原本目的相反了!!

                1.宏名和形参表必须在同一行且中间不能有空格

                2.宏形参不分配内存空间,因此无需说明其类型

                3.调用带参宏只是符号替换,不存在参数传递问题

                4.宏调用中的实参可以是表达式,但对实参表达式并不计算,直接用它替换宏定义中的参数

                5.宏定义字符串内的形参,通常用括号括起来,避免出现错误

                6.宏定义必须书写在一行中,如有必要可加续航符"\"

                7.调用有参宏的实参表达式中不要用 ++/-- 运算符

                8.宏定义字符串中的“#形参”表示将形参扩展为用双引号括起来的实参表达式,#N ->"N"

                9.宏定义字符串中的"##形参"表示将形参扩展为实参表达式并与前面的字符粘连在一起

                        ID##1 -> ID1

                10.用有参宏取代函数可以提高程序的执行效率,但会占用更多的磁盘和内存空间,

                        因此适用于实现那些频繁使用的简单功能

示例如下:

//宏函数演示
//gcc -E -o define.i define.c; vim define.i; gcc -o define define.i; ./define
#include <stdio.h>
#define SQUARE_1(X) (X*X) //定义宏函数求一个数的平方
#define SQUARE_2(X) ((X)*(X)) //定义宏函数求一个数的平方
#define SUB(X, Y)   ((X)-(Y)) //定义宏函数求相减
#define MAX(x, y)   ((x)>(y)?(x):(y)) //求最大数
#define IS_EVEN(n)  ((n)%2 == 0)//判断是否是偶数,如果是返回1,否则返回0
int main(void) {
    printf("%d\n", SQUARE_1(10));//10*10
    printf("%d\n", SQUARE_1(3+7));//3+7*3+7
    printf("%d\n", SQUARE_2(10));//(10)*(10)
    printf("%d\n", SQUARE_2(3+7));//(3+7)*(3+7)
    printf("%d\n", SUB(10, 5)); //(10)-(5)
    int a = 10, b = 20;
    printf("%d\n", MAX(a, b)); //(a)>(b)?(a):(b) 
    printf("%lg\n", MAX(3.2, 3.1)); //(3.2)>(3.1)?(3.2):(3.1)
    printf("%d\n", IS_EVEN(a));//(a)%2 == 0
    printf("%d\n", IS_EVEN(a+1));//(a+1)%2 == 0
    printf("%d\n", IS_EVEN(a+2));//(a+2)%2 == 0
    return 0;
}

取消宏、gcc -D设置宏和预定义宏

        #undef

                取消一个已定义的宏,令其宏名处于未定义状态

                #undef PI

        预定义宏有:

                __FILE__ : 所在文件名%s

                __LINE__: 所在行号 %d

                __FUNCTION__/__func__ : 所在函数名 %s

                __DATE__ : 编辑日期%s

                __TIME__ : 编译时间 %s

        gcc的 -D选项的妙用,功能:

                可以通过-D选项给程序传递常量宏

示例:

//gcc的-D选项的妙用,功能:可以通过-D选项给程序传递常量宏
//gcc -DSIZE=5 -DEND=\"tarena\" -o define2 define2.c
#include <stdio.h>
int main(void) {
    int a[SIZE] = {0};
    //初始化数组
    for(int i = 0; i < SIZE; i++)
        a[i] = i + 1;
    //打印数组
    for(int i = 0; i < SIZE; i++)
        printf("%d ", a[i]);
    printf("\n");
    printf("%s\n", END);
    //调试宏 
    int *p = NULL;
    if(!p) {
        printf("空指针:%s-%s,%s,%s,%d\n", 
                            __DATE__, __TIME__, 
                            __FILE__, __FUNCTION__, 
                            __LINE__);//前后各两个下划线
        return -1;
    }
    return 0;
}

条件编译指令

        #if 常量表达式 :如果常量表达式的值非零

        #ifdef 宏名 :如果宏名已定义

        #ifndef 宏名 :如果宏名未定义

        #elif 常量表达式 :否则如果常量表达式的值非零

        #else :否则

        #endif :结束判断

        常量表达式 :字面值/ defined(宏名) /&&/||

                根据不同条件,编译不同部分,会产生不同目标代码

        记住!!:当不满足编译条件时,会被 gcc -E 编译时忽略掉代码!!

        #if 0

                代码

        #endif       中间的代码全被注释

示例如下:

//条件编译
#include <stdio.h>
int main(void) {
    //#if演示
    //gcc -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
    //gcc -DA=1 -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
#if A==1
    printf("1.\n");
#endif//必须和#if配对
    //#if...#else
    //gcc -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
    //gcc -DB=1 -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
#if B==1
    printf("2.\n");
#else
    printf("3.\n");
#endif 
    //#ifdef或者#ifndef...#else演示
    //gcc -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
    //gcc -DC -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
//#ifdef C
#ifndef C
    printf("4.\n");
#else //可以不加
    printf("5.\n");
#endif
    //#if defined ...#else演示
    //gcc -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
    //gcc -DD -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
    //gcc -DE -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
    //gcc -DD -DE -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
    //gcc -DE -DD -E -o if.i if.c; vim if.i; gcc -o if if.i; ./if
#if defined(D) 
    printf("6.\n");
#elif !defined(D) && !defined(E)
    printf("7.\n");
#else
    printf("8.\n");
#endif
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值