------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、不带参数的宏定义
1.一般形式
#define 宏名 字符串
比如#define ABC 10
右边的字符串也可以省略,比如#define ABC
2.作用
它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。
接下来写个程序根据圆的半径计算周长
3.使用习惯与注意
1> 宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误
2> 对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作。比如:
3> 在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开宏名的源程序进行语法检查
4> 宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef命令
5> 定义一个宏时可以引用已经定义的宏名
#define R 3.0
#define PI 3.14
#define L 2*PI*R
#define S PI*R*R
二、带参数的宏定义
1.一般形式
#define 宏名(参数列表) 字符串
2.作用
在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换
3.使用注意
1> 宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串
2> 带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,一般用一个
3> 计算结果最好也用括号括起来
5.与函数的区别
从整个使用过程可以发现,带参数的宏定义,在源程序中出现的形式与函数很像。但是两者是有本质区别的:
1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行
示例:
/*
1.所有的预处理指令都是以#开头
2.预处理指令分3种
1> 宏定义
2> 条件编译
3> 文件包含
3.预处理指令在代码翻译成0和1之前执行
4.预处理的位置是随便写的
5.预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾,可以用#undef取消宏定义的作用
6.宏名一般用大写或者以k开头,变量名一般用小写
*/
#include
//#define kCount 4
int main()
{
char *name = "COUNT";
printf("%s\n", name);
#define COUNT 4
int ages[COUNT] = {1, 2, 67, 89};
for ( int i = 0; i
/*
1.带参数的宏定义效率比函数高
*/
/*
int sum(int a, int b)
{
return a + b;
}*/
#include
#define sum(v1, v2) ((v1)+(v2))
#define pingfang(a) ((a)*(a))
int main()
{
// pingfang(5+5) (10*10)
// pingfang(5+5)
// pingfang(5+5) (35)
// pingfang(5+5)/pingfang(2)
int c = pingfang(5+5)/pingfang(2);
printf("c is %d\n", c);
/*
int c = sum(2, 3) * sum(6, 4);
printf("c is %d\n", c);*/
/*
int a = 10;
int b = 20;
int c = sum(a, b);
printf("c is %d\n", c);
//int c = sum(a, b);*/
return 0;
}
条件编译的概念
在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行),这就是条件编译。
一、基本用法
1 #if 条件1
2 ...code1...
3 #elif 条件2
4 ...code2...
5 #else
6 ...code3...
7 #endif
1> 如果条件1成立,那么编译器就会把#if 与 #elif之间的code1代码编译进去(注意:是编译进去,不是执行,很平时用的if-else是不一样的)
2> 如果条件1不成立、条件2成立,那么编译器就会把#elif 与 #else之间的code2代码编译进去
3> 如果条件1、2都不成立,那么编译器就会把#else 与 #endif之间的code3编译进去
4> 注意,条件编译结束后,要在最后面加一个#endif,不然后果很严重(自己思考一下后果)
5> #if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才产生的、才有使用的意义
二、举个例子
1 #include
2
3 #define MAX 11
4
5 int main ()
6 {
7 #if MAX == 0
8 printf("MAX是0");
9 #elif MAX > 0
10 printf("MAX大于0");
11 #else
12 printf("MAX小于0");
13 #endif
14 return 0;
15 }
在第3行定义了一个宏MAX,当然在开发中这个MAX可能被定义在其他头文件中,现在只是为了方便演示,就写到main函数上面了。注意第7到第13行的条件编译语句。
由于MAX为11,所以#elif的条件成立,第10行代码将会被编译进去,其实编译预处理后的代码是这样的:
1 /*stdio.h文件中的内容将会代替#include
2
3 int main ()
4 {
5 printf("MAX大于0");
6 return 0;
7 }
代码变得非常简洁,输出结果:
三、其他用法
1.#if defined()和#if !defined()的用法
#if 和 #elif后面的条件不仅仅可以用来判断宏的值,还可以判断是否定义过某个宏。比如:
1 #if defined(MAX)
2 ...code...
3 #endif
如果前面已经定义过MAX这个宏,就将code编译进去。它不会管MAX的值是多少,只要定义过MAX,条件就成立。
条件也可以取反:
1 #if !defined(MAX)
2 ...code...
3 #endif
如果前面没有定义过MAX这个宏,就将code编译进去。
2.#ifdef和#ifndef的使用
* #ifdef的使用和#if defined()的用法基本一致
1 #ifdef MAX
2 ...code...
3 #endif
如果前面已经定义过MAX这个宏,就将code编译进去。
* #ifndef又和#if !defined()的用法基本一致
1 #ifndef MAX
2 ...code...
3 #endif
如果前面没有定义过MAX这个宏,就将code编译进去。
示例:
#include
// 只要写了#if,在最后面必须加上#endif
//#define A 5
int main()
{
#ifndef A
//#ifdef A
//#if !defined(A)
printf("哈哈\n");
#endif
//int a = 10;
/*
if (a == 10)
{
printf("a是10\n");
}
else if (a == 5)
{
printf("a是5\n");
}
else
{
printf("a其他值\n");
}*/
/*
#if (A == 10)
printf("a是10\n");
#elif (A == 5)
printf("a是5\n");
#else
printf("a其他值\n");
#endif
*/
return 0;
}
文件包含
一、基本概念
文件包含就是#include,它可以将一个文件的全部内容拷贝另一个文件中。
二、一般形式
1.第1种形式#include <文件名>
直接到C语言库函数头文件所在的目录中寻找文件
2.第2种形式 #include "文件名"
系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找
示例:
int sum(int a, int b)
{
return a + b;
}
#ifndef LISI_H
#define LISI_H
int sum(int a, int b);
#endif
#ifndef WANGWU_H
#define WANGWU_H
int minus(int a, int b);
#endif
/*
1.<>表示系统自带的文件,""表示自定义的文件
2.不允许循环包含,比如a.h包含b.h,b.h又包含a.h
*/
#include "lisi.h"
#include "wangwu.h"
#include
int main()
{
int c = sum(10, 19);
printf("c is %d\n", c);
return 0;
}
typeof
1.作用:给已经存在的类型起一个新的名称
2.使用场合:
1> 基本数据类型
2> 指针
3> 结构体
4> 枚举
5> 指向函数的指针
示例:
#include
typedef int MyInt;
typedef MyInt MyInt2;
// 给指针类型char *起一个新的类型名称String
typedef char * String;
/*
struct Student
{
int age;
};
typedef struct Student MyStu;
*/
/*
typedef struct Student
{
int age;
} MyStu;
*/
typedef struct
{
int age;
} MyStu;
/*
enum Sex {Man, Woman};
typedef enum Sex MySex;
*/
typedef enum {
Man,
Woman
} MySex;
typedef int (*MyPoint)(int, int);
int minus(int a, int b)
{
return a - b;
}
int sum(int a, int b)
{
return a + b;
}
/*
struct Person
{
int age;
};
typedef struct Person * PersonPoint;
*/
typedef struct Person
{
int age;
} * PersonPoint;
int main()
{
// 定义结构体变量
struct Person p = {20};
PersonPoint p2 = &p;
//struct Person *p2 = &p;
//MyPoint p = sum;
//MyPoint p2 = minus;
//int (*p)(int, int) = sum;
//int (*p2)(int, int) = minus;
//p(10, 11);
//MySex s = Man;
//enum Sex s = Man;
//enum Sex s2 = Woman;
// struct Student stu3;
//MyStu stu = {20};
//MyStu stu2= {21};
return 0;
}
void test2()
{
String name = "jack";
printf("%s\n", name);
}
void test()
{
int a;
MyInt i = 10;
MyInt2 c = 20;
MyInt b1, b2;
printf("c is %d\n", c);
}
#include
//#define Integer int
//typedef int Integer;
//typedef unsigned long int MyInt;
#define String2 char *
typedef char * String;
int main()
{
/*
int a,b;
int a;
int b;
*/
//s1、s2是char *指针
String s1, s2;
/*
String s1;
String s2;
*/
s1 = "jack";
s2 = "rose";
// s3才是char *指针,s4只是char
String2 s3, s4;
/*
char *s3, s4;
char *s3;
char s4;
*/
//String2 s3 = "jake";
/*
String s1;
String s2;
*/
//Integer i = 10;
return 0;
}
static和extain关键字
1.extain函数
先来理解2个概念:
外部函数:如果在当前文件中定义的函数允许其他文件访问、调用,就称为外部函数。C语言规定,不允许有同名的外部函数。
内部函数:如果在当前文件中定义的函数不允许其他文件访问、调用,只能在内部使用,就称为内部函数。C语言规定不同的源文件可以有同名的内部函数,并且互不干扰。
接下来就演示在一个源文件中调用另外一个源文件定义的函数,比如在main.c中调用one.c中定义的one函数。
注意点:
外部函数:定义的函数能被本文件和其他文件访问
1> 默认情况下所有函数都是外部函数
2> 不允许有同名的外部函数
内部函数:定义的函数只能被本文件访问,其他文件不能访问
1> 允许不同文件中有同名的内部函数
static对函数的作用:
1> 定义一个内部函数
2> 声明一个内部函数
extern对函数的作用:
1> 完整地定义一个外部函数
2> 完整地声明一个外部函数
(extern可以省略,默认情况下声明和定义的函数都是外部函数)
示例:
void test();
//void test2();
int main()
{
test();
//test2();
return 0;
}
//void test()
//{
//
//}
static void test2()
{
}
#include
// 声明一个内部函数
static void test2();
// 完整地定义一个外部函数
/*
extern void test()
{
printf("调用了test函数\n");
}*/
// 默认情况下,所有的函数都是外部函数,所以可以省略extern
void test()
{
printf("调用了test函数\n");
test2();
}
// 定义一个内部函数
static void test2()
{
printf("调用了test2函数\n");
}
全局变量分2种:
外部变量:定义的变量能被本文件和其他文件访问
1> 默认情况下,所有的全局变量都是外部变量
1> 不同文件中的同名外部变量,都代表着同一个变量
内部变量:定义的变量只能被本文件访问,不能被其他文件访问
1> 不同文件中的同名内部变量,互不影响
static对变量的作用:
定义一个内部变量
extern对变量的作用:
声明一个外部变量
static对函数的作用:
定义和声明一个内部函数
extern对函数的作用:
定义和声明一个外部函数(可以省略)
示例:
#include
/*
static修饰局部变量的使用场合:
1.如果某个函数的调用频率特别高
2.这个函数内部的某个变量值是固定不变的
*/
void test()
{
static double pi = 3.14;
double zc = 2 * pi * 10;
int a = 0;
a++;
printf("a的值是%d\n", a); // 1
/*
static修饰局部变量:
1> 延长局部变量的生命周期:程序结束的时候,局部变量才会被销毁
2> 并没有改变局部变量的作用域
3> 所有的test函数都共享着一个变量b
*/
static int b = 0;
b++;
printf("b的值是%d\n", b); // 3
}
int main()
{
for (int i = 0; i<100; i++) {
test();
}
test();
test();
test();
return 0;
}
#include
void test();
// 定义一个外部变量
//int a; 这么多个a都是代表同一个a
//int a;
//int a;
//int a;
//int a;
// 定义一个内部变量
static int b;
// 声明一个外部变量
//extern int a;
int main()
{
//b = 10;
//test();
extern int a;
a = 10;
/*
a = 10;
test();
printf("a的值是%d\n", a);*/
return 0;
}
int a;
#include
int a;
static int b;
void test()
{
printf("b的值是%d\n", b);
/*
printf("a的值是%d\n", a);
a = 20;*/
}