C基础课程笔记总结9-预处理,宏,以及其他

课程:预处理,宏

预处理语句是不需要用分号结尾的,其他任何语句都需要用分号结尾,预处理指令有3个:

1:宏定义。

2.条件编译。

3:文件包含。


预处理指令是在代码翻译成0和1之前执行的指令,代码运行需要首先编译,翻译为0和1,然后在链接,之后运行

所有的预处理指令都是以“#”号开头,位置随意,即可以定义在内部,也可以定义在外部,作用域由定义的那一行开始,一直到文件结束。。

宏定义:#define,分为两种:带参数或不带参数。

不带参数的宏定义多用于更改数组的长度,在循环条件中可以不用频繁更改代码,良好的编程习惯。

宏定义的常量名全大写,但是如果程序中有和宏定义常量同名的字符串,编译时不对字符串进行替换处理。

并且宏名是一个标识符,要按照标识符命名规则命名,通常使用"_"来代替“.”,可以定义一个空的宏名,即不做任何文本替换。

如果在文件结束之前想让宏定义失效,使用指令:#undef 宏名,在这一行开始,这个宏名就不再有作用。
宏名的命名规范:一般全大写,或者以k(表示常量)开头之后再全大写。


带参数的宏: #define 宏名(参数) 表达式,这个指令表示把左边的宏名完全代替为右边的表达式(完全替换即纯文本替换,写什么就是什么),

表达式中最好每一个都加上括号,否则极易出现未知的语义错误,加括号是良好的编程习惯。

对于简单的运算,用宏定义也能实现相关功能,用函数也能实现相关功能,但是宏定义是纯粹的文本替换,并没有生成结果,效率更高,调用函数时系统需要先找到函数,

然后在分配内存空间。


条件编译:


条件编译即满足条件时,某个代码(块)才会编译为0和1,写入。o文件中执行,类似if else else elseif,最后的if一定不要忘记写。

如果不写条件编译,则在程序中对于所有的if。。。else。。。语句都会全部编译,使用条件编译效率更高。

条件编译在ios中很常用,条件编译格式如下:

#if......

#elif...........注意是  e l i f,  不是else

#else.........这个才是else

#endif    这个一定不能忘记写,有了#if 一定要有#endif,否则出现未知错误因为如果没有#endif,在预处理指令执行后,除了满足条件的那个语句被保留编译为01,这条语句之后的所有一切,

包括其他代码,和配对的大括号,都会全部不编译为01,因此,系统编译时会报错,而加入#endif之后表示作用if 和elseif 之间。


条件编译是预处理命令,因此必须保证条件编译中所涉及的相关变量在编译函数之前就存在,一般和宏定义搭配使用,保证最先存在。

还有一些不常用的操作如下:

#if define ()   =#ifdef 宏常量:如果定义了一个对应的宏常量,编译此语句。

#if !define() = #ifndef 宏常量:如果没有定义一个对应的宏常量,编译此语句。

书写习惯,在写了#if之后必须写上#endif


文件包含:

需要调用文件外部函数时,必须先声明这个外部函数,可以通过包含那个函数文件的。h文件来实现,在。h文件中,声明了所有的相关函数

文件包含不允许循环包含,即不能你包含我,我包含你,在文件中,函数只能定义一次,而函数的声明可以声明N次,每一次 编译器都会翻译,降低了编译器的效率。

为了避免浪费,可以在相关的头文件中加入以下代码:

#ifndef ABC

#define ABC

声明相关函数

#endif     有了#if。。。一定要写#endif

则在其他文件中声明该。h文件时,根据预处理指令的执行顺序,声明函数永远只声明一次,但在多个。h文件中,有可能定义同名的宏,因此在实际开发中,通常使用文件名作为宏定义变量,以此保证宏名的唯一性。

用<>表示包含系统文件,用“”表示包含自定义的文件


关键字:typedef

typedef比较常用,可以简化代码量

格式如下:

typedef 类型名  类型别名

例如:

 typedef int  MyInt 即定义了一个INT类型的别名,还可以个MYint 在定义另一个别名。因此typedef作用就是定义别名,配合结构体变量可以少写代码量,也可以配合匿名结构体,即可以搭配自定义类型使用,来简化代码量定义方法灵活多变。

也可以配合枚举类型enum来使用,,还有指向结构体变量的指针,  还有指向函数的指针,也可以配合typedef使用,但是格式略有不同。

typedef既可以定义在内部,也可以定义在外部。

typedef使用的注意点:

在某些场合中使用宏定义 #define  纯文本替换,也可以完成typedef的功能,但始终要记住,宏定义只是纯粹的问题替换而已,而typedef是根据一个实在存在的类型去定义替换的,因此还是有区别的,不建议使用宏定义替换类型


关键字:static和extern

在实际开发中static经常使用,而extern(外部的)在面试中常见。

这两个关键字都可以作用于函数和变量。

外部函数:定义的函数可以本文件和外部文件访问,默认所有函数都是外部函数,可以在其他文件中访问,省略了extern关键字,即 使用extern可以声明定义一个外部函数,默认省略不写。

整个项目的不同文件中的外部函数不能同名,会有冲突

内部函数:定义的函数只可以在本文件中访问,使用static定义的函数,如果要定义和声明一个内部函数,不能省略static 关键字,内部函数相当于对外部不可见,在不同文件中可以有同名的内部函数。

对变量的作用:

变量也分为两种:全局变量

全局变量又分为两种:外部全局变量,内部全局变量,顾名思义。在默认情况下,所有的全局变量都是外部变量,并且默认初始化值是0,所有文件都可以访问,

同一种变量类型,同一个变量名,不论声明多少次,不论是在哪个文件中,都是指向同一个全局变量。但是如果是不同变量类型,同变量名呢??????

C中全局外部变量使得数据封装性很差,任意外部都可以改变变量的值。

而全局内部变量,只能是所在定义的文件访问,其他文件无法访问。用static修饰定义在函数外部的变量即可,有定义的那一行开始生效,直到当前文件结束。

而extern作用于变量,则表示该变量为外部变量,既可以在函数内部声明,也可以在外部声明。

extern对于函数的作用,既可以声明也可以定义(extern可以省略)

extern对变量的作用,只能是声明变量 

static对于函数的作用,既能定义也可以声明。

static对于变量既可以定义,也可以声明变量。


static对局部变量的作用

局部变量必须手动初始化,全局变量有默认的初始化值。

局部变量即是定义在函数内部的变量,当这个函数被调用时,才会在内存中开辟存储空间,当这个函数执行完毕时,分配个这个函数的空间也将释放,这些空间中的变量也会消失,

再次调用同一个函数时,又会重新分配一个新的内存空间。

当用static定义一个局部变量时,则这个变量的在该函数第一次调用时分配内存空间,在函数执行完毕后不会消失,当再次调用该函数时,就能继续使用这个static局部变量,这个局部变量一直存在于同一个内存地址中,直到整个程序结束后内存才释放,

但是这个变量的作用范围仍是该函数内部,使用static定义后并没有改变这个变量的作用域。即对于这个变量而言,它将会被所有的同一个函数所共享,但不是被所有函数共享

使用static修饰局部变量,可以在一定程度上优化性能。对于一个函数而言,如果函数中有某个变量需要频繁使用,但是该变量的值是一直不变的,则可以将变量定义为一个static局部变量

例如求圆的周长或面积时所使用的圆周率,则可以定义为一个static局部变量,为何不用全局变量呢?因为只有调用到求周长和面积函数时才需要用到pi。


递归:

问:函数的内部递归也会一直分配新的内存空间吗??

答:是的,递归也是函数调用,每一次函数调用都会分配内存空间(不是在同一块内存空间,而是另外的空间),所以递归十分消耗系统资源,多层递归时有可能造成系统崩溃。

设计递归函数首先先找出思路,找出重复步骤,并且要有一个终止条件。

















































































































































































































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值