目录
注: 笔记代码均在 Linux 环境下测试运行.
Linux 下 C 程序的编写和运行
- Terminal 中,打开/创建 test.c 文件:
nano test.c
- 编写 C 程序, 退出并保存
#include<stdio.h> // 双斜杠, 单行注释 /* 多行注释 C 语言中, int main() 和 void main() 是一样的; C++ 中, 只接受 int main() 这种定义方式. */ int main() { printf("This is a test code.\n"); return 0; }
- 编译 C 程序:
(此处使用 gcc 进行编译, 程序中如使用了 C++ 语法, 需使用 g++ 进行编译)gcc test.c -o test
- 运行目标程序:
("./"不能少)./test
关键字 & 标识符 Keywords & Identifier
As C is a case sensitive language, all keywords must be written in lowercase.
- 字符集 Character Set
- 字母 Alphabets
- 大写 Uppercase : A B C ... X Y Z
- 小写 Lowercase : a b c ... x y z
- 数字 Digits : 0 1 2 3 4 5 6 7 8 9
- 特殊字符 Special Characters (e.g. 空白字符 White space Characters : Blank space, newline, horizontal tab, carriage return and form feed.)
- 字母 Alphabets
- 关键字
- 关键字 Keywords
Keywords are predefined. - 保留字 Reserved Words
Reserved words used in programming that have special meanings to the compiler.
- 关键字 Keywords
- 标识符 Identifier
- Identifier refers to name given to entities such as variables, functions, structures etc.
- Identifiers must be unique.
- Rules for naming identifiers :
- A valid identifier can have letters (both uppercase and lowercase letters), digits and underscores.
- The first letter of an identifier should be either a letter or an underscore.
- You cannot use keywords like int, while etc. as identifiers.
- There is no rule on how long an identifier can be. However, you may run into problems in some compilers if the identifier is longer than 31 characters.
C 程序的编译链接过程
- 预处理:
宏定义展开\头文件展开\条件编译等, 同时将代码中的注释删掉; - 编译:
检查语法; 语法无误后, 将预处理后的文件编译生成汇编文件.s; - 汇编:
将汇编文件生成目标文件.o(二进制文件); - 链接:
C 语言编写的程序是需要依赖各种库文件(系统组件)的, 所以要把编译之后的目标文件库链接到最终的可执行程序.exe中去.(可能链接多个目标文件)
一般情况下我们所说的“编译器”实际上也包括了链接器
- 编译器 Compiler
编译就是将我们编写的源代码“翻译”成计算机可以识别的二进制格式,它们以目标文件的形式存在;- 预处理器 Preprocessor
- 编译器 Compiler
- 汇编器 Assembler
- 链接器 Linker
链接就是一个“打包”的过程,它将所有的目标文件以及系统组件组合成一个可执行文件。
1. 预处理 Preprocess
- 预处理一般是指在源程序被转换为二进制代码之前, 对源文件进行预编译.
- 预处理功能:
- 宏定义
- 条件编译
- 文件包含
- 删除注释
1.1 宏 macro
A macro is *a fragment of code that is given a name.
宏替换, 只做字符序列的替换工作, 不作任何语法检查.
- 简单宏 macro
#define 标识符 字符序列
- 宏函数 function-like macro
#define 标识符() 字符序列
- 预定义的宏 Predefined Macro:
__DATE__
: A string containing the current date__FILE__
: A string containing the file name__LINE__
: An integer representing the current line number__STDC__
: If follows ANSI standard C, then the value is a nonzero integer__TIME__
: A string containing the current date
- 宏函数 & 函数 的区别:
- 宏函数, 也是宏, 只做简单的 字符替换, 不会浪费新的堆栈空间, 使用多少次, 就替换多少次, 就编译多少次.
- 函数, 只会编译一次, 但每次调用都会临时占用新的堆栈空间.
#include <stdio.h> #define A 5 #define MAX(a,b) ((a)>(b) ? (a) : (b)) // 加 () 防止 运算优先级导致运算出错 int main() { // 使用预定义的宏 打印系统当前时间 printf("Current date & time:\t%s %s\n\n", __DATE__, __TIME__); printf("Enter the a Integer: "); int a, b; scanf("%d %d", &a, &b); printf("MAX(%d,A) = %d\nMAX(%d,A) = %d\n", a, MAX(a,A), b, MAX(b,A)); return 0; }
#include<stdio.h> // 多行声明一个宏时, 一行结尾处加上字符'\', 然后紧跟回车, '\'后面不要有其他任何字符. #define A int main() {\ B\ C\ return D;\ } #define B printf("This is a macor that could be undefined\n"); #define C printf("This is a macor test\n"); #define D 0 // #undef B // 取消已定义的宏 B. 取消定义后, 预编译时不能再使用 B 做宏替换 (如继续使用则会报错) A
1.2 条件编译 conditional compilation
In C programming, you can instruct preprocessor whether to include a block of code or not.
#include<stdio.h> #if !defined A // 等价与 `#ifndef A`, 表示如果没有定义宏 A, 则执行以下代码 // #ifndef A #define A "This is A.\n" #endif // 标志最近的一个条件编译(#if !defined A)的结束 #define B 0 #if defined B // 等价于 `#ifdef B`, 表示如果定义了宏 B, 则执行以下代码 // #ifdef B #define B "This is B.\n" // 重新定义宏 B, 覆盖原来的定义 #else #define C This is C. #endif // 标志最近的一个条件编译(#if defined B)的结束 // 每个条件编译都需要用 `#endif` 作为结束 int main() { printf(A); printf(B); // printf("C\n"); // 字符串中没有宏替换, 只有一般字符和控制字符等 return 0; }
- It's similar to a if statement with one major difference.
- The if statement is tested during the execution time to check whether a block of code should be executed or not whereas.
- The conditionals are used to include (or skip) a block of code in your program before execution.
- Uses of Conditional
- use different code depending on the machine, operating system
- compile same source file in two different programs
- to exclude certain code from the program but to keep it as reference for future purpose
1.3 文件包含
- .c 文件, 存放具体功能的实现, 也可直接用于文件包含;
- .h 文件, 存放声明, 一般用于声明同名 .c 文件中的函数, 并用于文件包含.
#include<***>
引入 <标准头文件> 如: #include<stdio.h> 编译系统在系统头文件所在目录搜索包含头文件 stdio.h#include"***"
引入 "自定义头文件" 如: #include"myfile.h" 编译系统首先在 当前的源文件所在的目录 中查找 myfile.h , 如没有找到, 再转到系统头文件所在的目录(即系统指定的 包含文件目录)搜索.
#ifndef STDIO_H // 如果没有定义 STDIO_H, 则执行以下代码 #define STDIO_H // 定义宏 STDIO_H #include<stdio.h> // 包含头文件 stdio.h #endif // 结束这个条件编译 int main() { printf("可以通过 条件编译, 来解决文件的 重复包含 问题.\n"); return 0; }
Here, stdio.h is a header file. The #include preprocessor directive replaces the above line with the contents of stdio.h header file.
That's the reason why you need to use #include <stdio.h> before you can use functions like scanf() and printf().
2. 编译 Compile
- 将C语言代码转换成CPU能够识别的二进制指令.
- 大致包括 词法分析、语法分析、语义分析、性能优化、生成可执行文件 五个步骤.
- 通常一个目标文件中至少有两个段:代码段 & 数据段
- 编译是针对一个源文件的,有多少个源文件就需要编译多少次,就会生成多少个目标文件。
- 编译: .c/.cpp/.h ---> .s
- 汇编: .s ---> .o
- 对于 Visual C++,目标文件的后缀是.obj
- 对于 GCC,目标文件的后缀是.o
3. 链接 Link
- 编译只是将我们自己写的代码变成了二进制形式(并不是最终的可执行文件.exe),它还需要和系统组件(比如标准库、动态链接库等)结合起来,这些组件都是程序运行所必须的.
- 链接(Link)其实就是一个“打包”的过程,它将所有二进制形式的 目标文件 & 系统组件 组合成一个可执行文件.
- 随着我们学习的深入,我们编写的代码越来越多,最终需要将它们分散到多个源文件中,编译器每次只能编译一个源文件,生成一个目标文件,这个时候,链接器除了将目标文件和系统组件组合起来,还需要将编译器生成的多个目标文件组合起来.
4 运行 How does C program work?
- All valid C programs must contain the
main()
function. The code execution begins from the start of themain()
function. - The
eturn 0;
statement inside themain()
function is the "Exit status" of the program. It's optional.
Reference Materials:
https://www.cnblogs.com/mickole/articles/3659112.html
https://www.cnblogs.com/carpenterlee/p/5994681.html
https://www.programiz.com/c-programming
Why Learn C Programming?
- C helps you to understand the internal architecture of a computer, how computer stores and retrieves information.
- After learning C, it will be much easier to learn other programming languages like Java, Python, etc.
- Opportunity to work on open source projects. Some of the largest open-source projects such as Linux kernel, Python interpreter, SQLite database, etc. are written in C programming.