define,typedef,inline 的区别
define
1.用于在代码中创建宏定义,将一个标识符替换为一个表达式或语句。例如:
#define PI 3.14159
#define SQUARE(x) ((x) * (x))
这样,程序中所有出现的 PI
都将被替换为 3.14159,SQUARE(x)
则被替换成了 (x) * (x)
。
使用 #define
定义宏和使用函数定义是有很大区别的。使用 #define
定义宏只是简单的文本替换,没有类型检查和语法分析,而函数定义则会进行类型检查、语法分析,并分配栈空间存储局部变量和函数参数等信息。因此,使用函数定义更加安全和可靠,而使用宏定义则可以更灵活地编写代码。
类型检查是指编译器在编译程序的过程中对变量、表达式、函数参数和返回值等数据类型的正确性进行检查。如果程序中存在类型不匹配的情况,编译器会给出警告或错误提示。通过类型检查,可以帮助程序员避免一些常见的编程错误,例如类型不匹配、越界访问、空指针引用等等。
2. 可以⽤来防⽌头⽂件重复引⽤
#ifndef HEADER1_H //if not defined 条件编译 检查当前头文件是否已经被引用过了
#define HEADER1_H //如果没有被引用过,则定义一个名为指定名称的宏
程序段1 //如果没有被引用过,编译程序段1,程序段1一般就是HEADER1_H的主体内容
#else
程序段2// 如果被引用过,忽略程序段1
#endif
条件指示符#ifndef的最主要目的是防止头文件的重复包含和编译。条件编译当然也可以用条件语句来实现, 但是用条件语句将会对整个源程序进行编译,生成的目标代码程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2,生成的目标程序较短。
3.define不分配内存,给出的是⽴即数,有多少次使⽤就进⾏多少次替换
立即数指的是在程序执行过程中直接出现的常量值,而不是存储在内存中的变量,比如上面的例子中PI直接被替换成数值,而不是像我们平时那样定义一个变量double PI = 3.14159
4.在编译的预处理阶段起作用,也就是在编译代码之前进行的处理,将所有的宏定义进行替换
typedef
1.用于创建新的数据类型别名。它的语法如下:
typedef 原类型 新类型名;
例如:
typedef unsigned int uint;
这样,uint
就是 unsigned int
的别名,可以在程序中使用 uint
代替 unsigned int
。
因为它的作用是定义一个新的名称来表示一个已有的数据类型。如果定义的名称已经存在或者没有对应的数据类型,就会导致编译错误。因此在使用typedef之前需要对已有的数据类型进行判断。
2. 在静态存储区中分配空间,在程序运⾏过程中内存中只有⼀个拷⻉
内存中的拷贝通常是指一个数据在内存中有多个副本,也就是有多个变量名指向同一个内存地址。这种情况在程序中比较常见,例如在函数调用时传递参数,会将参数的值复制一份到函数内部的堆栈中。在这种情况下,原始变量和复制变量在内存中的位置不同,但它们的值相同。
typedef unsigned int uint;
uint a = 1;
uint b = a;
uint c = a;
这个别名在程序中的使用和原始类型是一样的,只是为了让程序员更方便地使用。当程序中使用my_int类型时,编译器会将其解释为int类型,因此只会有一个int类型的内存副本,而不是多个拷贝。
3. 是在编译、运⾏的时候起作⽤
inline 内联
inline int max(int a, int b) {
return a > b ? a : b;
}
int main() {
int x = 10, y = 20;
int z = max(x, y); // 调用 max 函数
return 0;
}
提示编译器将函数内容直接嵌入调用它的地方,而不是像普通函数一样进行函数调用。
- 可以提高程序的执行效率,因为函数调用时需要保存现场、压栈、跳转等操作,而这些操作在函数嵌入时可以省略。
- 内联函数是⼀种特殊的函数,会进⾏类型检查
- 不能存在任何形式的循环语句
- 不能存在过多的条件判断语句
- 内联函数声明必须在调⽤语句之前