1.程序执行过程
C语言的编译和链接是将源代码转换为可执行程序的过程。下面是C语言编译和链接的基本步骤:
-
预处理:在编译前,预处理器会对源代码进行。它会处理以"#"开头的预处理指令,#include和#define,并将它们替换为应的内容。
-
编译:编译器将预处理后的源代码转换为汇编代码。它会检查语法错误和类型错误,并相应的错误信息。
-
汇编:汇编器将汇编代码转换为机器码,就是目标。目标文件包含了可执行程序的二制指令和。
-
链接:链接器将目标文件与其他必要的库文件进行链接,生成最终的可执行程序。它会解析函数调用和全局量引用,并将它们与相应的定义进行关联。
在链接过程中有两种常见的链接方式:
静态链接:静态链接器将目标文件和库文件的代码和数据合并到一个单独的可执行文件中。这意味着所有的代码和数据都被复制到最终的可执行文件中,使得可执行文件可以独立运行。
动态链接:动态链接器在运行时将目标文件和库文件的代码和数据链接到可执行程序中。这意味着多个程序可以共享同一个库文件,减少了可执行文件的大小。动态链接还可以在库文件更新时,无需重新编译可执行文件。
2.常见的预定义符号
__FILE__ // 进行编译的源文件
__LINE__ // 文件当前的行号
__DATE__ // 文件被编译的日期
__TIME__ // 文件被编译的时间
__STDC__ // 如果编译器遵循 ANSI C,其值为 1,否则未定义
好像这样看是不是还是不太了解,我们直接上代码,一起观察这些预定义符号
至于__STDC__:
是一个预定义的宏,用于指示编译器是否符合ISO C标准(ANSI C标准)。如果编译器遵循ISO C标准,则该宏会被定义为1;否则,它未定义或者被定义为其他值。
至于这些符号具体在项目中有没有用,很有用,你完全可以用它们去找到你的程序具体在哪个代码,哪一行出现了问题,并且很多大型项目中,都会用它写一个名叫日志系统的模块
3.#define的应用
我们还是直接来看代码好了
当然在宏中也有特殊符号‘#’和‘##’,
我想对他们的使用应该有一定了解了
注意:宏只是将内容替换,很可能因为你在定义宏的时候没有明确给出括号,而导致运行的结果和你期待的结果完全不同。
4.宏和函数的区别
5.取消宏定义(#undef)
当然还有(#if,#else,#else if,#endif)跟if,else表达的含义一样
6.#error
7.#include头文件的包含
在包含头文件的时候,我们有很大的可能会对同一个头文件,进行多次包含,在预编译的时候将你所包含的头文件全部替换成文本,给代码的编译,链接等增加不必要的负担。为了避免这种事情的发生,我们可以使用
#ifndef和#indef来检测如果多次包含,就不进行包含
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// 在这里放置头文件内容
#endif // SOME_HEADER_FILE_H
当然这种没有我接下来介绍的好用。
#pragma once//只需这一行便足够
8.每期一问
写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
考察:
offsetof
宏的实现