C 预处理指令

预处理指令

  • 1. #define 预处理指令( 用来定义宏)
    • 1.1 宏可以用来给数字起名字
      • 除了在程序里定义宏代表的数字,也可以在编译命令里面使用-D选项,就可以指定宏所代表的数字
        • #define PI 3.14f //用宏给3.14f这个数字起名字叫π

        • gcc test2.cc -DPI=3.14f

      • 如果编写程序时需要用到某个数字但是又不知道它的具体数值,就可以在程序里先用宏代表它,然后在编译的时候在临时指定。
//希望程序可以得到一张彩票里的随机数,每个随机数在1到36之间。然后再把这些随机数显示在屏幕上。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE = 0
int main() {
    //写程序时并不知道彩票里包含多少随机数,无法定义数组里到底有多少个存储区
    //用SIZE宏名称带代表数组里存储区个数
    int arr[SIZE] = {0};
    int num = 0;
    srand(time(0));
    for (num = 0; num <= SIZE -1; num++) {
        //得到一个 1到36 之间的随机数
       arr[num] =  rand() % 36 + 1; 

    }

    for (num = 0; num <= SIZE - 1 ; num ++) {
        printf("%d\n", arr[num]);
    }
    return 0;
}

 /*
g++  -DSIZE=100 test.cc
由SIZE决定输出随机数的数量。
*/
    • 1.2 宏也可以给计算公式起名字
      • 宏的参数表示公式里的未知数
#include <stdio.h>
#define PI 3.14f
//定义一个宏叫CIRCLE, 宏的参数都是没有类型名称的
//因为宏的参数都是用替换的方式进行处理的,所以r不一定得代表数字,
#define CIRCLE(r) 2 * PI * r

int main() {
    int radius = 0;
    printf("请输入半径: ");
    scanf("%d", &radius);
    printf("周长是%g\n", CIRCLE(radius));

    return 0;
}

/*
//gcc 使用-E编译,编译器只会去完成所有预处理指令的处理,会把所有的宏都替换掉,然后显示出来

g++  -E test.cc

output:
...
...
int main() {
    int radius = 0;
    printf("请输入半径: ");
    scanf("%d", &radius);
    printf("周长是%g\n", 2 * 3.14f * radius);

    return 0;
}
*/
    • 1.3 编写宏和编写函数不一样的地方
      • 如果希望宏向函数里传递一个数字就必须把宏编写成表达式,用表达式的结果表示要传递的数字
      • 宏可以通过参数直接修改函数的存储区内容,因为宏的参数直接代表了函数的存储区,可以直接在宏里修改参数
//计算绝对值和相反数
#include <stdio.h>
//下面说的函数就是主函数
//宏不可以使用自己的存储区和函数之间进行数值传递, 宏的参数直接代表了函数的存储区
//所有能当数字的宏,必须要把它写成一个表达式,表达式本身是可以当数字使用的,将表达式结果传递给函数
#define ABS(n) n >=0 ? n : 0 -n 

//宏的参数直接代表了函数的存储区,不需要像普通函数那样用指针修改调用函数的存储区,宏直接在宏里修改参数就可以改变主函数的存储区
#define NEG(n) n = 0 -n

//函数里会有一个专门的存储区用来放返回值的,调用函数就会得到那个返回值,但是宏不行,宏没有这样的存储区
int abs(int val) {
    if (val >= 0) {
        return val;
    }
    else {
        return 0 - val;
    }
}

void neg(int *p_val) {
    *p_val = 0 - *p_val;
}

int main() {
    int val = 0;
    printf("请输入一个数字: ");
    scanf("%d", &val);

    printf("绝对值是:%d\n", abs(val));
    printf("绝对值是:%d\n", ABS(val));
    
    neg(&val);
    printf("相反数是:%d\n", val);
    printf("相反数的相反数是:%d\n", NEG(val));
    
}

/*
请输入一个数字: -1
绝对值是:1
绝对值是:1
相反数是:1
相反数的相反数是:-1
*/
    • 1.4 宏注意事项总结
      • 如果希望宏向函数传递一个数字就必须把宏编写成一个表达式,用表达式的结果表示要传递的数字
      • 宏可以通过参数直接修改函数的存储区内容
      • 宏不能保证优先计算宏内部的操作符,所以编写宏的时候,应该把宏写在一对小括号里
      • 宏不能保证优先计算宏参数里的操作符,所以编写宏的时候应该把参数写在一对小括号里
      • 使用宏的时候不要用自增或者自减的结果做参数
#include <stdio.h>
#define SUB(x, y) ((x) - (y))
int main() {
    printf("SUB(10,5)是%d\n", SUB(10, 5));
    printf("20 - SUB(10, 5)是%d\n", 20 - SUB(10, 5));
    printf("SUB(20, 10 - 5)是%d\n", SUB(20, 10 - 5));
}

/*
output:
SUB(10,5)是5
20 - SUB(10, 5)是15
SUB(20, 10 - 5)是15
*/
    • 1.5 宏操作符
      • # 操作符可以把宏参数转换成字符串字面值
      • ## 操作符可以把代表标识符(变量名称, 函数名称等)的宏参数和其他内容连接得到一个新的宏标识符
#include <stdio.h>
#define STR(n) #n
#define PTR(n) p_##n
int main() {
    int val = 0;
    int *PTR(val) = &val; 
    STR(2 + 3);
    return 0;
}

/*
gcc -E test.cc

output:
...
...
int main() {
    int val = 0;
    int *p_val = &val;
    "2 + 3";
    return 0;
}
*/
  • 2. 条件编译
    • 编译时从一组语句里选择一组编译而忽略其他组
      • #ifdef/#ifndef…#esle…#endif 结构可以根据一个宏名称是否被定义过,从两句语句里选择一组进行编译
#include <stdio.h>
int main() {
#ifdef YI
    printf("1\n");
#else
    printf("2\n");
#endif
    return 0;

}

/*
gcc test.cc
output: 1

gcc test.cc -EYI
output:2
*/
    • #if…#elif(任意多次)…#else…#endif 结构可以根据任意逻辑表达式从多组语句里选择一组进行编译
      代码实例略
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值