预处理指令
什么是预处理指令:
在我们的文件翻译成0和1之前做的操作我们称之为预处理指令。一般情况预处理指令都是以#号开头的。
宏定义的格式
不带参数的宏定义:
#define 宏名 值
宏定义的作用:
会在程序翻译成0和1之前, 将所有宏名替换为 宏的值
宏定义在什么时候替换
源代码 --> 预处理 -->汇编 -->二进制 -->可执行程序
注意:宏定义后面不要写分号
宏定义规范:
一般情况宏名都大写, 多个单词之间用_隔开, 并且每个单词全部大写。
有的公司又要求宏名以k开头, 多个单词之间用驼峰命名。
宏定义的作用域:
从定义的那一行开始, 一直到文件末尾。
虽然默认情况下宏定义的作用域是从定义的那一行开始, 一直到文件末尾. 但是我们也可以通过对应的关键字提前结束宏定义的作用域。(#undef COUNT)
带参数的宏定义:
#define SUM(v1, v2) v1+v2
#define 代表要定义一个宏
SUM 宏的名称
(v1, v2) 参数, 注意点, 不需要写数据类型
v1+v2 用于替换的内容
宏定义并不会做任何运算, 无论是有参数还是没有参数都仅仅是在翻译成0和1之前做一个简单的"替换"
带参数的宏定义注意点
1.一般情况下建议写带参数的宏的时候, 给每个参数加上一个()
2.一般情况下建议写带参数的宏的时候, 给结果也加上一个()
如:
#define PF(v1) ((v1)*(v1))
什么时候用带参数的宏定义什么时候用函数?
如果函数内部的功能比较简单, 仅仅是做一些简单的运算那么可以使用宏定义, 使用宏定义效率更好, 运算速度更快。
如果函数内部的功能比较复杂, 不仅仅是一些简单的运算, 那么建议使用函数。
条件编译
#define DEBUG 1 // 0是调试阶段 1是发布阶段
#if DEBUG == 0
// 调试阶段
#define NJLog(format, ...) printf(format,## __VA_ARGS__)
#else
// 发布阶段
#define NJLog(format, ...)
#endif
条件编译和选择结构if的共同点
都可以对给定的条件进行判断, 添加满足或者不满足都可以执行特定的代码
条件编译和选择结构if的区别
1.生命周期不同
if 运行时
#if 编译之前
2.#if需要一个明确的结束符号 #endif
为什么需要一个明确的结束符号?
如果省略掉#endif, 那么系统就不知道条件编译的范围, 那么会将满足条件之后的第二个条件之后的所有内容都清除
3.if会将所有的代码都编译到二进制中
#if只会将满足条件的部分一直到下一个条件的部分 编译到二进制中
条件编译的优点
1.缩小应用程序的大小
应用场景:
用于调试和发布阶段进行测试
调试阶段: 程序写代码的阶段
发布阶段: 上传到AppStore的阶段
预处理指令什么时候执行? 编译之前 。
变量什么时候定义? 执行了才会定义。
注意点: 条件编译不能用来判断变量, 因为不在同一个生命周期。
一般情况下, 条件编译是和宏定义结合在一起使用的。
#include <stdio.h>
#define SCORE 100
//#define COUNT 50
int main(int argc, const char * argv[]) {
#ifdef SCORE // 判断是否定义了后面的宏
printf("score\n");
#elif COUNT
printf("count\n");
#else
printf("OTHER\n");
#endif
#ifndef SCORE // 是不是没有定义名称叫做SCORE的宏
printf("no score\n");
#else
printf("score\n");
#endif
/*
#if defined(SCORE) // 判断是否定义了SCORE这个宏
printf("score\n");
#else
printf("no score\n");
#endif
#if !defined(SCORE) // 判断是否没有定义SCORE这个宏
printf("no score\n");
#else
printf("score\n");
#endif
*/
return 0;
}
文件包含
#include <>
<>会先去编译器环境下查找, 找不到再去系统的环境下查找
#include ""
""会先在当前文件查找, 找不到再去编译器环境下查找, 找不到再去系统的环境下查找
作用:
将""或者<>中的内容完全拷贝过来
注意:
如何正确的编写.h文件
如何防止循环拷贝 A拷贝B, B拷贝A
间接拷贝问题 A拷贝B, B拷贝C, C拷贝D
typedef
什么是typedef, 它有什么作用
typedef可以给一个已知的数据类型起别名 (外号)
利用typedef给数据类型起别名的格式:
typedef 原有的数据类型 别名(外号);
注意:
1. typedef不仅能给系统原有的数据类型起别名, 也可以给一个自定义的数据类型起别名。
2. 利用typedef给数据类型起别名, 并不会生成一个新的数据类型, 仅仅是给原有的类型起了一个别名而已。
typedef可以给指向函数的指针起别名
// functionPotinter == int(*functionPotinter)(int , int)
typedef int(*functionPotinter)(int , int);
int main(int argc, const char * argv[]) {
// 9如何定义变量 : 数据类型 变量名称;
// int (*sumP)(int , int ) = sum;
functionPotinter sumP = sum;
printf("sum = %i\n", sumP(10 , 20));
// int (*minusP)(int, int) = minus;
functionPotinter minusP = minus;
printf("minus = %i\n", minusP(20, 10));
return 0;
}
可以给指针起别名
// String == char *
typedef char * String;
void test4()
{
// char *name = "lnj";
// 注意: 如果给指针起别名之后, 那么以后利用别名定义变量就不用再加*了
String name = "lnj";
printf("name = %s\n", name);
}
可以给枚举类型起别名
// 1.先定义枚举类型, 再给枚举类型起别名
/*
enum Gender
{
kGenderMale,
kGenderFemale
};
typedef enum Gender SEX;
*/
// 2.定义枚举类型的同时给枚举类型起别名
/*
typedef enum Gender
{
kGenderMale,
kGenderFemale
} SEX;
*/
// 3.定义枚举类型的同时给枚举类型起别名, 并且省略枚举原有类型名称
typedef enum
{
kGenderMale,
kGenderFemale
} SEX;
给结构体类型起别名
// 1.先定义结构体类型, 再给类型起别名
/*
struct Person
{
int age;
double height;
char *name;
};
// SPerson == struct Person
typedef struct Person SPerson;
*/
// 2.定义结构体类型的同时, 给结构体类型起别名
/*
typedef struct Person
{
int age;
double height;
char *name;
} SPerson;
*/
// 3.定义结构体类型的同时, 给结构体类型起别名, 并且省略掉原有类型的名称
typedef struct
{
int age;
double height;
char *name;
} SPerson;
给基本数据类型起别名
// Integer == int
typedef int Integer;
typedef Integer myInt;
// int float doulbe char
void test1()
{
int num = 10;
printf("num = %i\n", num);
Integer age = 30;
printf("age = %i\n", age);
myInt score = 99;
printf("score = %i\n", score);
}
typedef和宏定义的区别
一般情况下如果要给数据类型起一个名称建议用typedef, 不要用define
typedef int myInt;
#define Integer int
typedef char * String;
#define MY_STRING char *
const关键字
const修饰的变量内容不可改变,变量变为常量。
int const num = 10;
printf("num = %i\n", num);
//num = 55;//编译报错,不能改变变量的值
printf("num = %i\n", num);
const修饰的指针变量,指针变量指向的地址的内容可以改变,但是指针保存的地址不能变。
char const * name = "lnj";
printf("name = %s\n", name);
name = "lk";
printf("name = %s\n", name);
const可以写在char这个数据类型的左右都可,习惯写在最前面。
终于学完了基础部分,以后多加练习,有些重要的知识点要回头反复敲代码,不然记不住,同时进度继续,下一步学oc。