登录  | 立即注册

游客您好!登录后享受更多精彩

扫一扫,访问微社区

QQ登录

只需一步,快速开始

开启左侧

[学习笔记] 编译预处理指令

[复制链接]
发表于 2018-2-18 20:03:11 | 显示全部楼层 |阅读模式
学习笔记
学习科目: C语言
学习安排: 关于全局变量和staric的补充,宏,工程的意义,头文件的自建与使用,声明与定义
开始时间: 2018-02-18
结束时间:
我们先来回顾一下全局变量,
下面这个代码只是为了验证全局变量可以被每一个函数调用
#include<stdio.h>

int f(void);
int gAll = 12;

int main()
{
    printf("in %s gAll = %d\n",__func__,gAll);//__func__这是C语言预定义的宏,表示的就是它所在的函数
    f();
    printf("agn in %s gAll = %d\n",__func__,gAll);
    return 0;
}

int f(void)
{
    printf("in %s gAll = %d\n",__func__,gAll);
    gAll+=2;
    printf("agn in %s gAll = %d\n",__func__,gAll);
    return gAll;
}
这里需要做一些补充
1. 没有做初始化的全局变量会得到0值
    指针会得到NULL值
2. 只能用编译时刻已知的值里初始化全局变量
    比如上面的gAll
    我们可以给它赋值 12 或任何的数字
    但是我们不能这样 int gAll = f();
    也不能这样 int gAll = 12;
               int g2 = gAll;
    不过我们可以这样 const int aAll=12;
                     int g2 = gAll;
3. 他们的初始化发生在main函数之前

之前的笔记里面有 static 关键字
它的作用是将本地变量变为静态本地变量
而实际上,静态本地变量是特殊的全局变量
它们位于相同的内存区域,
静态本地变量具有全局变量的生存期,函数内的局部作用域

编译预处理指令
C语言中 # 开头的是编译预处理指令,当然不止C语言使用
它不是C语言的成分,但是C语言程序离不开它

#define 用来定义一个宏

#include<stdio.h>

const double PI = 3.14159;

int main()
{
    printf("%f\n",2*PI*3.0);
    return 0;
}
c99 中我们可以这样做,用 const
c99之前是怎么解决的?

#define PI 3.14159
PI是这个宏的名字, 3.14159 是这个宏的值
这是编译预处理指令,编译前编译器会将所有的 PI 换成 3.14159

#define <名字> <值>
注意结尾没有分号,这不是一条C语言的语句
名字必须是一个单词,值可以是任何东西
在C语言的编译器开始编译之前,会将程序中的名字换成值
如果一个宏的值中还有其他宏的名字,也会被替换
如果一个宏的值超过一行,行末需要加\
宏里面也可以有注释

预定义的宏
__LINE__  表示所在行的行号
__FILE__  表示源文件的文件名
__DATE__  编译时刻的日期
__TIME__  编译时刻的时间
__STDC__

还可以定义像函数的宏
#define cube(x) ((x)*(x)*(x))
宏可以带参数
x就是这个参数,将来是会被替换的

带参数的宏的原则
一切都要带括号
    整个宏的值要带括号
    每一个参数都要带括号
这样能保证我们的代码不会出错

宏定义可以嵌套,也可以有多个参数
#define min(a,b) a>b?a:b
min = a>b?a:b 这是条件运算符作用类似于 if else
if(a>b){
    max=b;
}else
    max=a;

在大型程序的代码中,宏使用的非常普遍
可以非常复杂,如生产函数
部分的宏也会被 inline 函数取代
其它编译预处理指令
error 条件编译

工程建立
为什么需要工程?
当我们的 .c 文件很大,有很多个函数的时候,
我们可以将它分为多个 .c 文件,
当然这两个文件要太同一个工程下面,我们编译运行它,同样是可以的
编译器会将这两个文件链接起来

头文件
我们可以把函数声明放在 .h 文件下,使用时 #include就可以直接使用这个函数
插入的头文件可以有两种引用方式
""和<>两种
那么如何选择呢
    ""要求编译器首先在当前目录下寻找这个文件,
    如果没有再到编译器指定的目录去找
    <>让编译器只在指定目录去找

当然编译器知道自己的标准库的头文件在哪
环境变量和编译器命令行参数也可以指定寻找头文件的目录
#include<stdio.h>
#include"max.h"

int main()
{
    int a=6;
    int b=12;
    printf("%d",max(a,b));
    return 0;
}

int max(int a,int b){
    if(a>b){
        b=a;
    }
    return b;
}
我在当前目录下写了一个max.h文件,上面就可以省略申明

#include
1.#include 不是用来引入库的
2. stdio.h等头文件里面只有函数的声明,而函数的库在其他地方,
    在某个 .lib文件里面
3. 现在的编译器默认会引入所有的标准库

我们在使用和定义这个函数的时候都应该 #include 这个头文件
一般的做法就是任何.c文件都有对应同名的.h文件,
把所有对外公开的函数原型和全局变量的声明都放进去

全局变量是可以让所有.c文件使用的,
如果在全局变量加上static关键字,就只能在这个.c文件内使用

变量的声明

int i ;这个是变量的定义,如果我们要发到头文件内,是需要声明的
extern int i;这个就是变量声明

声明和定义
声明是不产生代码的东西
    函数原型,变量声明,结构声明,宏声明,枚举声明,类型声明,inline函数
定义是产生代码的东西
    函数,全局变量//就这两种

一个.c文件中只能有声明,并且不能重复声明,但是程序结构复杂的时候又很难避免重复
所以
我们一般在头文件中加上这几句//标准头文件结构
#ifndef _MAX_H_ //如果没有定义这个宏,执行下面的指令
#define _MAX_H_ //定义宏
...
...
#endif // _MAX_H_//结束上面的if

  # 空指令,无任何效果
  #include 包含一个源代码文件
  #define 定义宏
  #undef 取消已定义的宏
  #if 如果给定条件为真,执行下面指令与程序
  #ifdef 如果宏已经定义,执行下面指令与程序
  #ifndef 如果宏没有定义,执行下面指令与程序
  #elif 如果前面的#if给定条件不为真,当前条件为真,执行下面指令与程序
  #endif 结束一个#if……#else条件编译块
  #error 停止编译并显示错误信息
这些都是预处理指令
宏定义时可能出现##,它的意思是链接前后数据
例如:
    #define conn(str) str##myname
    conn(123);
    这句的意思就是等价于123myname

好懒~~不想说~~~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表