C语言预处理

1. 发生时机

预处理操作,不是c语言语句,因此语句末尾没有分号,在预处理阶段完成,本质是替换操作
发生时段:
在这里插入图片描述

2. 宏

2.1. 不带参宏

2.1.1. 宏常量

#define定义的宏,只能在一行内表达(换行符表示结束而非空格),如果想多行表达,则需要加续行符

#define PI 3.14\
15926535
int main() 
{
	printf("%f", PI); // 3.1415926535
	return 0;
}

宏常量,常被const/enum变量取代,用于定义文件路径则被常用

#define FILEPATH "/Users/mingqi/Desktop/my_code/c:c++/file.c"

宏常量的缺陷

#define N 2 + 3;
// #define N (2 + 3);
int main()
{
  int num = N * 2;
  printf("num = %d", num); // 8 10
  return 0;
}

解决这些问题,要不吝惜使用括号

2.1.2. 宏类型

宏可以给类型起别名,因其缺点,常被typedef取代

#define CHARP char *
int main()
{
  CHARP p, q;
  printf("p = %d, q = %d\n", sizeof(p), sizeof(q)); // 8 1
  return 0;
}

2.2. 带参宏(宏函数)

常将短小精悍的函数进行宏化,这样可以嵌入到代码中,减少调用的开销。但是代价就是编译出的文件可能会变大
宏函数常常一行表达不完,如多行,采用续行符进行接续

2.2.1. 宏函数

#define S(a, b) a*b
area = S(3,2);
// 宏展开:area = 3 * 2;
// 注:宏名和参数间不能用空格
#define POWER(x) x*x
x = 4; y = 6;
z = POWER(x, y);
// 宏展开:z = x+y * x+y;
// 一般写成:#define POWER(x) ((x) * (x))
// 宏展开:z = ((x+y) * (x+y))

使用define,别吝惜括号
常见宏函数

#define MAX(a, b) (a>b) ? a : b

2.2.2. 宏出错处理函数

#define F_PRINT_ERR(e)        \
  do                          \
  {                           \
    if (e == NULL)            \
    {                         \
      printf("open error\n"); \
      exit(-1);               \
    }                         \
  } while (0)

2.3. 取消宏

#define MAX 23
int main()
{
  printf("%d\n", MAX); // 23
#undef MAX
  printf("%d\n", MAX); // ERROR
  return 0;
}

3. 条件编译

依据条件,判断哪些程序段参与编译

3.1. 单双路(#ifdef / #ifndef #else #endif)

#if #else #endif
#ifdef #ifndef #else #endif

#define X86
int main()
{
#ifdef X86
  printf("xxxxx");
#else
  printf("aaaa");
#endif
  return 0;
}

3.2. 单双多路(#if #elif #endif)

#define X86 1
#define MIPS 2
#define POWERPC 3
#define MACHINE POWERPC
int main()
{
#if MACHINE == X86
  printf("hello 86");
#elif MACHINE == MIPS
  printf("hello mips");
#elif MACHINE == POWERPC
  printf("hello powerpc");
#endif
  return 0;
}

3.3. 编译期指定宏 gcc -D

4. 头文件包含(#include)

4.1. 包含的意义

全写入,被包含的文件中
包含是支持嵌套的

4.2. 包含的方式

4.2.1. 方式<>

#include <stdio.h>,从系统指定路径中搜索包含头文件,linux中的系统路径为(/usr/include)

#include <stdio.h> -> #include "stdio.h" -> #include <stdio.h>

4.2.2. 方式" "

#include “myString.h”,从工程当前路径中搜索包含头文件,如果当前工程路径下没有,则到系统路径下搜索包含

#include "myString.h" -> #include <myString.h>

4.3. 多文件编程

4.3.1. 多文件编程意义

多文件编程的好处:

  1. 方便管理,协同开发
  2. 便于分享与加密(作成函数库)

4.3.2. 多文件编程的前提

C语言是以文件为单位进行编译的,编译器只需要函数声明即可,链接阶段提供实现就可以完成生成可执行文件
在这里插入图片描述

4.4. 定义头文件

在这里插入图片描述

4.4.1. 头文件自包含

.c文件中存在相互调用的关系,自包含可以免去了多余的前向声明

5. 其他

5.1. #运算符 利用宏创建字符串

将替换符字符串化,解决字符串中,不可被替换的参数问题。

// #define str(x) #x
// #define str(x) "aaaaaxaaaaa"
#define str(x) "aaaaa" #x "aaaaa"
#define printSqr(x) printf("sqr(" #x ") = %d \n", x *x);
int main()
{
    printf("%s\n", str(100)); // aaaaa100aaaaa
    printSqr(5);              // sqr(5) = 25
    return 0;
}

5.2. ##运算符 预处理的粘合剂

解决了参数变量与宏展开,无法一一对应的问题

// #define sum(a, b) (aa + bb)
#define sum(a, b) (a##a + b##b)
#define XNAME(n) x##n
int main()
{
    printf("%d\n", sum(2, 3)); // 55
    int XNAME(1) = 14;
    printf("x1 = %d\n", XNAME(1)); // 14
    return 0;
}
#define PRINT_XN(n) printf("x" #n " = %d\n", x##n)
int main()
{
    int XNAME(1) = 14;
    int XNAME(2) = 28;
    printf("x1=%d, x2=%d\n", XNAME(1), XNAME(2)); // x1=14, x2=28
    PRINT_XN(1);
    PRINT_XN(2);
    return 0;
}

5.3. 预定义宏

DATE:进行预处理的日期("MMmm dd yyyy"形式的字符串蚊子)
FILE:代表当前源代码文件名的字符串蚊子
LINE:代表当前源代码中的行号的整数常量
TIME:源文件编译时间,格式:“hh:mm:ss”
func:当前所在函数名
在打印调试信息时打印这两个宏__FILE__和__LINE__可以给开发者非常有用的提示

void why_me();
int main()
{
    printf("The file is %s.\n", __FILE__);
    printf("The date is %s.\n", __DATE__);
    printf("The time is %s.\n", __TIME__);
    printf("The line is %d.\n", __LINE__);
    printf("The func is %s.\n", __func__);
    why_me();
    return 0;
}
void why_me()
{
    printf("The func is %s.\n", __func__);
    printf("The file is %s.\n", __FILE__);
    printf("The line is %d.\n", __LINE__);
}
  • 32
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qi妙代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值