int main()
{
//printf("%s\n", __FILE__);//打印所在文件夹位置
//printf("%d\n", __LINE__);//打印当前所在行号
//printf("%s\n", __DATE__);//打印当前系统日期
//printf("%s\n", __TIME__);//时间
//printf("%s\n", __FUNCTION__);//他所在当前函数的函数名 打印结果为main
return 0;
}
如何使用以上预处理命令 如下
int main()
{
//printf("%s\n", __FILE__);//打印所在文件夹位置
//printf("%d\n", __LINE__);//打印当前所在行号
//printf("%s\n", __DATE__);//打印当前系统日期
//printf("%s\n", __TIME__);//时间
//printf("%s\n", __FUNCTION__);//他所在当前函数的函数名 打印结果为卖弄
int i = 0;
FILE* pf = fopen("log.txt", "a+");//以追加的形式是写入 可以应用日志
if (pf == NULL)
{
perror("fopen\n");
return 1;
}
for (i = 0; i < 10; i++)
{
fprintf(pf, "%s %d %s %s %d\n", __FILE__, __LINE__, __DATE__, __TIME__, i);
}
fclose(pf);
pf = NULL;
//printf("%d\n", __STDC__);//编译器支持ansi标准就可以编译出结果。 vs不支持 如果支持编译结果为1(linux)
return 0;
}
define
define 定义符号
//#define 是定义符号的
#define M 1000//怎么工作。在预处理阶段就把下面的M改成了1000
#define reg register//相当于重赋名了 以后register都可以用reg代替
#define do_forever for(;;)//相当于前面的内容被转换为后面的for(;;)
int main()
{
reg int num = 0;
do_forever;//如果想写一个死循环直接这样写就行
int m = M;
printf("%d\n", m);
return 0;
}
#define CASE break;case//定义了一个CASE 他的内容是break;case
int main()
{
int n = 0;
switch (n)
{
case 1://第一个不能替换
CASE 2:
CASE 3:
}
return 0;
}
define 定义宏
宏的申明:#define name(parament-list)stuff
其中parament-list是一个由逗号隔开的符号表,他们可能出现在stuff中
()里是参数列表 后面的stuff是我们的内容。 前面的参数可以替换到我们的内容里去。
注意:参数列表的左括号必须与name紧邻。
上面的什么意思举例如下
#define 定义宏
括号很重要
#define SQUARE(x) x*x
int main()
{
printf("%d", SQUARE(3));//结果为9
printf("%d\n", SQUARE(3+1));//结果为7
printf("%d\n", 3 + 1 * 3 + 1); 上面为什么 因为宏是完成替换的 替换过来就像左边所写的一样
return 0;
}
#define SQUARE(X) ((X)*(X))加上括号这样的得出的结果才是想要的4×4=16
#define DOUBLE(X) ((X)+(X))
int main()
{
printf("%d\n", SQUARE(3+1));//
printf("%d\n", 10 * DOUBLE(4));
printf("%d\n", 10 * ((4) + (4)));运算结果为80
printf("%d\n", 3 + 1 * 3 + 1);
printf("%d\n", 3 * 3);
return 0;
}
#define 替换规则
#define M 100
#define MAX(X, Y) ((X)>(Y)?(X):(Y))
int main()
{
int max = MAX(101, M);
//int max = MAX(101, 100);//上面第一条的意思 直接替换后就是这样的
printf("M = %d\n", M);//注意的第二条 这个表达式中前面的“M=%d”这里面的M不会被替换
return 0;
}
#和##
#可以把一个参数插入到字符串中
void print(int x)
{
printf("the value of c is %d\n", x);//发现函数的方式做不到 of后面的不能更改
}
int main()
{
//printf("hello world\n");
//printf("hello " "world\n");这两个打印出来的结果一致
int a = 10;
print(a);
//the value of a is 10 希望能打印出这样的一句话
int b = 20;
print(b);
//the value of b is 20
int c = 30;
print(c);
//the value of c is 30
return 0;
}
接下来我们尝试用宏的方式实现
以上就是#号的用处。不加#号是替换 加上之后就变成了内容所对应的字符串
它会变成这样// //printf(“the value of ““a”” is %d\n”, a);
#define print(X) printf("the value of "#X" is %d\n", X);
int main()
{
//printf("hello world\n");
//printf("hello " "world\n");
int a = 10;
print(a);
//the value of a is 10
int b = 20;
print(b);
//the value of b is 20
int c = 30;
print(c);
//the value of c is 30
return 0;
}
按以上代码运行后可得到想要的结果。接下来把他变得更完善些
#define PRINT(X, FORMAT) printf("the value of "#X" is "FORMAT"\n", X);
int main()
{
//printf("hello world\n");
//printf("hello " "world\n");
int a = 10;
PRINT(a, "%d");
//printf("the value of ""a"" is %d\n", a);
//the value of a is 10
int b = 20;
PRINT(b, "%d");
//printf("the value of ""b"" is %d\n", b);
//the value of b is 20
int c = 30;
PRINT(c, "%d");
//the value of c is 30
float f = 5.5f;
PRINT(f, "%f");
printf("the value of ""F"" is ""%f""\n", f);
return 0;
}
##如下
#define CAT(X,Y,Z) X##Y##Z
int main()
{
int class101101 = 100;
printf("%d\n", CAT(class, 101, 101));//##作用就是把他么当作一个符号class101101所以这个打印结果为100
return 0;
}
带副作用的宏参数
#define MAX(X, Y) ((X)>(Y)?(X):(Y)) 求两数的较大值
int main()
{
int a = 5;
int b = 8;
int m = MAX(a++, b++);
//int m=((a++) > (b++) ? (a++) : (b++)); 为什么结果为9 就是因为define定义需要先替换。
printf("m=%d\n", m);
return 0;
}//输出结果为9 符号的简单替换,不要当成函数,就是符号替换 define先于计算
宏和函数的对比
求两数的较大值 选择1的话效率更高些 原因有以下两种
**与类型无关,所以宏更方便 **
宏的劣势
以下是宏可以做到但是函数做不到的例子
#define MALLOC(num, type) (type*)malloc(num*sizeof(type)) //(type*)这是返回类型。malloc(num*sizeof(type))这是宏体
int main()
{
//malloc(10*sizeof(int)); 开辟函数空间。这样写比较麻烦 想写成下面那样 但是语法不支持 但是我们可以用宏定义一个
//malloc(10, int);
int*p = MALLOC(10, int);
//(int*)malloc(10 * sizeof(int)); 上面的会被替换成这样
return 0;
}
总结:简单用宏,复杂用函数
命令约定
#undef(取消定义)
#define M 100
int main()
{
int a = M;
#undef M//没加这个之前结果为100 加了后报错 因为加了后相当于 没有了之前的定义
printf("%d\n", M);
return 0;
}
命令行参数
命令行可以定义参数
比如以下代码在vs中会报错 报错原因是m未定义。但是在linux中编译的时候在命令行后定义m参数就可以执行
int main()
{
int arr[M] = { 0 };
int i = 0;
for (i = 0; i < M; i++)
{
arr[i] = i;
}
for (i = 0; i < M; i++)
{
printf("%d ", i);
}
return 0;
}
条件编译
int main()
{
#ifdef PRINT
printf("hehe\n");
#endif
return 0;
}//输出结果为空
如果最上面定义了如下
#define PRINT
int main()
{
#ifdef PRINT
printf("hehe\n");
#endif
return 0;
}//输出结果为hehe
常见的的条件编译指令
int main()
{
#if 0//常量表达式 0为假 1为真。为假就不执行
printf("hehe\n");
#endif
return 0;
}
以下写法也可以
#define PRINT 1
int main()
{
#if PRINT
printf("hehe\n");
#endif
return 0;
}
int main()
{
#if 1==1//打印结果为hehe 因为只要第一个为真后面的不会参与运算了
printf("hehe\n");
#elif 2==2
printf("haha\n");
#else
printf("heihei\n");
#endif
return 0;
}
#define TEST 0
#define HEHE 1
int main()
{
//如果TEST定义了,下面参与编译
//1
#ifdef TEST
printf("test1\n");
#endif
//2
#if defined(TEST)//与上面的意义相同
printf("test2\n");
#endif
//如果HEHE不定义,下面参与编译
//3
#ifndef HEHE
printf("hehe1\n");
#endif
//4
#if !defined(HEHE)
printf("hehe2\n");
#endif
return 0;
}
头文件包含
//库文件包含,C语言库中提供的函数的头文件使用<>
#include <stdio.h>
//本地文件包含,自定义的函数的头文件使用""
#include “add.h”
//<> 和 ""包含头文件的本质区别是:查找的策略的区别
//“” 1. 自己代码所在的目录下查找,2.如果第1不找不到,则在库函数的头文件目录下查找
//<> 直接去库函数头文件所在的目录下查找
vs环境标准头文件的路径
//VS2022C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt
//**
嵌套文件包含
如何防止头文件被包含两次
加#pragma once
第一句的意思是 如果没由包含 为真的话就会执行下面的一次。如果为假就停止
防止头文件被重复多次的包含