C语言面试之旅:掌握基础,探索深度(面试实战之c语言关键词中篇)
劝人的话就像清晨的闹钟,只对别人有用,却永远叫不醒自己。
----小新
一.预处理指令
(1)#define
& typedef
#define是C语言中定义的语法,是预处理指令,在预处理时进行简单而机械的字符串替换,不作正确性检查,只有在编译已被展开的源程序时才会发现可能的错误并报错。
typedef是关键字,在编译时处理,有类型检查功能。它在自己的作用域内给一个已经存在的类型一个别名,但不能在一个函数定义里面使用typedef。用typedef定义数组、指针、结构等类型会带来很大的方便,不仅使程序书写简单,也使意义明确,增强可读性。
例如:
#define PI 3.14159
typedef struct {
char name[50];
int age;
} Student;
注解:
PI就被定义为一个常量,值为3.14159。
(2) #include
这是预处理指令中最常用的函数之一,用于包含其他文件。
例如:
#include <stdio.h>
注解:
这个指令就会包含标准输入输出库。
(3)#if
, #ifdef
, #ifndef
, #else
, #elif
, #endif
这些是条件编译的预处理指令,用于有条件地编译程序。
例如:
#if defined(DEBUG)
// 只有在定义了DEBUG时才会编译这部分代码
#endif
(4)#undef
这个预处理指令用于取消已经定义的宏。
例如:
#define PI 3.14159
#undef PI
注解:
PI就被取消定义了。
(5) #line
,#error
,#pragma
这些是比较特殊的预处理指令,#line
用于改变编译器中的行号和文件名跟踪,#error
用于让编译器生成错误信息,#pragma
用于实现一些特定的编译器特性。这些指令的使用往往依赖于具体的编译器实现。
(6)__DATE__
, __TIME__
, __FILE__
, __LINE__
, __func__
这些是C99引入的预定义的宏,分别代表当前日期、时间、源文件名、行号和函数名。例如,__LINE__
就会在编译时被替换为当前源代码行号。
(7)__attribute__((...))
这个是在GCC和一些其他C编译器中使用的特性,用于设置函数属性、变量属性等。例如,__attribute__((noreturn))
就表示这个函数不会返回。
二.寄存器存储
(1) register
1.建议寄存器存储
通过使用 register
关键字,程序员可以向编译器建议将某个变量存储在寄存器中。寄存器是位于中央处理单元(CPU)内部的存储区域,它的访问速度比内存要快得多。因此,将变量存储在寄存器中可以提高程序的执行速度。
|
2.编译器决定
需要强调的是,register
只是一个建议,而非强制要求。编译器可以选择是否将变量存储在寄存器中。通常,编译器会根据代码的复杂性和寄存器的可用性来决定是否采纳这些建议。
3.限制使用
register
变量通常有一些限制,例如不能取地址或使用指针对其进行操作,因为寄存器变量不在内存中有地址。这也意味着 register
变量通常不能用于需要取地址的操作,如指针和数组的地址计算。
4.性能提升
使用 register
可以提高程序的性能,特别是在循环中对频繁访问的变量使用 register
可能会产生显著的性能提升。
三.共享全局变量
1.变量声明
通过使用 extern
,你可以在一个源文件中声明一个在另一个源文件中定义的全局变量,以便在当前源文件中使用它,而不需要重新定义。这对于在多个文件中共享全局变量非常有用。
// File1.c
int globalVar; // 定义全局变量
// File2.c
extern int globalVar; // 声明在其他文件中定义的全局变量
2.函数声明
类似于变量,你也可以使用 extern
来声明在其他源文件中定义的函数。这允许你在当前文件中使用这些函数而无需重新定义它们。
// File1.c
void someFunction(); // 定义函数
// File2.c
extern void someFunction(); // 声明在其他文件中定义的函数
3.解决多文件编程
extern
用于多文件编程中,特别是当你将程序拆分成多个源文件时,有助于确保这些文件之间的全局变量和函数能够正确共享。它允许你在一个文件中定义,而在其他文件中声明和使用这些全局实体。
4.避免重复定义
extern
声明允许你在一个文件中定义全局变量或函数,而在其他文件中声明,从而避免多次定义相同的变量或函数,这将导致链接错误。