1 _ _FILE_ _ //进行编译的源文件2 _ _LINE_ _ //文件当前的行号3 _ _DATE_ _ //文件被编译的日期4 _ _TIME_ _//文件被编译的时间5_ _STDC_ _//如果编译器遵循ANSI C,其值为1,否则未定义
我们用代码实现一下
#include<stdio.h>
int main()
{
printf("%s\n", __FILE__);
printf("%d\n", __LINE__);
printf("%s\n", __DATE__);
printf("%s\n", __TIME__);
return 0;
}
我们就可以得到该文件的信息
#include<stdio.h>
int main()
{
printf("%s\n", __STDC__);
return 0;
}
而我们打印__STDC__就会报错,说明VS是不支持ANSI C
2.#define定义常量
#include<stdio.h>
#define M 100
#define STR "hehe"
int main()
{
int a = M;
printf("%d\n", a);
printf("%s\n", STR);
return 0;
}
#include<stdio.h>
#define M 100;
#define STR "hehe"
//for循环的判断部分如果省略后,判断条件就恒为真,这个循环就是死循环
#define forever for( ; ; )
int main()
{
int a = M;
printf("%d\n", a);
printf("%s\n", STR);
forever;
return 0;
}
# define MAX 1000# define reg register // 为 register 这个关键字,创建⼀个简短的名字# define do_forever for(;;) // ⽤更形象的符号来替换⼀种实现# define CASE break;case // 在写 case 语句的时候⾃动把 break 写上。// 如果定义的 stuff 过⻓,可以分成⼏⾏写,除了最后⼀⾏外,每⾏的后⾯都加⼀个反斜杠 ( 续⾏符 ) 。# define DEBUG_PRINT printf( "file:%s\tline:%d\t \date:%s\ttime:%s\n" ,\__FILE__,__LINE__ , \__DATE__,__TIME__ )
思考:在define定义标识符的时候要不要在后面加上 ; ?
# define MAX 1000;# define MAX 1000
建议不要加上;,这样容易导致问题
比如下面的场景
if (condition)max = MAX;elsemax = 0 ;
# define name( parament-list ) stuff
其中的parament_list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:
参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
举例
#include<stdio.h>
#define SQUARE(X) X*X
int main()
{
int a = 5;
printf("%d\n", SQUARE(a));
return 0;
}
//我们分析一下
printf("%d\n", SQUARE(a));变成
printf("%d\n",a*a); //来运行的 结果为25;
如果我们改一下呢
#include<stdio.h>
#define SQUARE(X) X*X
int main()
{
int a = 5;
printf("%d\n", SQUARE(a+2));
return 0;
}
此时结果为17 为什么是这个结果呢,其实很简单,他是把
printf("%d\n", SQUARE(a+2));//替换成了
printf("%d\n",a+2*a+2);//5+2*5+2=17 //替换产生的表达式并没有按照预想的次序进行求值。
在宏定义上加上两个括号,这个问题便轻松的解决了:# define SQUARE(x) (x) * (x)这样预处理之后就产⽣了预期的效果:printf ( "%d\n" ,(a + 2 ) * (a + 2 ) );
定义中我们使⽤了括号,想避免之前的问题,但是这个宏可能会出现新的错误。
int a = 5 ;printf ( "%d\n" , 10 * DOUBLE(a));
#include<stdio.h>
#define DOUBLE(X) X+X
int main()
{
int a = 5;
printf("%d\n", 10 * DOUBLE(a));
return 0;
}
printf ( "%d\n" , 10 * ( 5 ) + ( 5 ));
乘法运算先于宏定义的加法,所以出现了 55 .
# define DOUBLE( x) ( ( x ) + ( x ) )
#include<stdio.h>
int main()
{
int a = 10;
int b = a+1;//b=11 a=10
int a = 10;
int b = ++a;//b=11 a=11 //带有副作用的
return 0;
}
#include<stdio.h>
#define MAX(a, b) ((a)>(b)?(a):(b))
//带有副作用的宏参数
//求2个整数的较大值
#define MAX(a, b) ((a)>(b)?(a):(b))
int max(int x, int y)
{
return x>y?x:y;
}
int main()
{
int a = 15;
int b = 9;
//int m = MAX(a++, b++);
int m = max(a++, b++);
//int m = ((a++)>(b++)?(a++):(b++));
//15 > 9 16
//17
printf("%d\n", m);//16
printf("a=%d b=%d\n", a, b);//17 10
return 0;
}
#define MAX(a, b) ((a)>(b)?(a):(b))
//函数 - 2
int max(int x, int y)
{
return x>y?x:y;
}
#define M 100
int main()
{
int m = MAX(M, 101);
printf("M = %d\n", M);
return 0;
}
# define MALLOC(num, type)\(type )malloc(num sizeof(type))...// 使⽤MALLOC( 10 , int ); // 类型作为参数// 预处理器替换之后:( int ) malloc ( 10 sizeof ( int ));
7.#和##
7.1#运算符
# define PRINT(n) printf( "the value of " #n " is %d" , n);
#include<stdio.h>
void Print(int n)
{
printf("the value of n is %d\n", n);
}
int main()
{
int a = 10;
Print(a);
int b = 20;
Print(b);
return 0;
}
我们看到并不是我们想要的结果
#include<stdio.h>
#define Print(n,format) printf("the value of "#n" is"format"\n",n)
int main()
{
int a = 10;
Print(a);
int b = 20;
Print(b);
return 0;
}
7.2##运算符
int int_max ( int x, int y){return x>y?x:y;}float float_max ( float x, float y){return x>yx:y;}
但是这样写起来太繁琐了,现在我们这样写代码试试:
//宏定义
# define GENERIC_MAX(type) \type type##_max(type x, type y)\{ \return (x>y?x:y); \}
GENERIC_MAX(int) //替换到宏体GENERIC_MAX(float)内后int##_max ⽣成了新的符号 int_max做函数名
GENERIC_MAX(float) //替换到宏体内后float##_max ⽣成了新的符号 float_max做函数名
int main()
{
//调⽤函数
int m = int_max(2, 3);
printf("%d\n", m);
float fm = float_max(3.5f, 4.5f);
printf("%f\n", fm);
return 0;
}
在实际开发过程中##使⽤的很少,很难取出⾮常贴切的例子。
# undef NAME// 如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除。
#include<stdio.h>
#define M 100
int main()
{
int a = M;
#undef M
int b = M + 2;
return 0;
}
#include<stdio.h>
#define M 100
int main()
{
int a = M;
#undef M
#define M 200
int b = M + 2;
return 0;
}
#include <stdio.h>
int main()
{
int array [ARRAY_SIZE];
int i = 0;
for(i = 0; i< ARRAY_SIZE; i ++)
{
array[i] = i;
}
for(i = 0; i< ARRAY_SIZE; i ++)
{
printf("%d " ,array[i]);
}
printf("\n" );
return 0;
}
//linux 环境演⽰gcc -D ARRAY_SIZE= 10 programe.c
#include<stdio.h>
#define FLAG 3
int main()
{
#if FLAG==2
printf("hehe\n");
#endif
return 0;
}
#include<stdio.h>
#define FLAG 2
int main()
{
#if FLAG==2
printf("hehe\n");
#endif
return 0;
}
#include<stdio.h>
#define FLAG 3
int main()
{
#if FLAG==1
printf("hehe\n");
#elif FLAG ==2
printf("haha\n");
#else
printf("heihei\n");
#endif
return 0;
}
1.# if 常量表达式//...# endif// 常量表达式由预处理器求值。如:# define __DEBUG__ 1# if __DEBUG__//..# endif2. 多个分⽀的条件编译# if 常量表达式//...# elif 常量表达式//...# else//...# endif3. 判断是否被定义# if defined(symbol)# ifdef symbol# if !defined(symbol)# ifndef symbol4. 嵌套指令# if defined(OS_UNIX)# ifdef OPTION1unix_version_option1();# endif# ifdef OPTION2unix_version_option2();# endif# elif defined(OS_MSDOS)# ifdef OPTION2msdos_version_option2();# endif# endif
12.1.1 本地⽂件包含
# include "filename"
1 /usr/include
VS环境的标准头⽂件的路径
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include// 这是 VS2013 的默认路径
注意按照⾃⼰的安装路径去找。
# include <filename.h>
# include "test.h" //test.c# include "test.h"# include "test.h"# include "test.h"# include "test.h"int main (){return 0 ;}
void test (); //test.hstruct Stu{int id;char name[ 20 ];};
# ifndef __TEST_H__# define __TEST_H__// 头⽂件的内容# endif //__TEST_H__或者# pragma once
13. 其他预处理指令
# error# pragma# line...不做介绍,⾃⼰去了解。# pragma pack() 在结构体部分介绍。