Files
Linux-C-Notes/Chapter1/C1-绪论.md
2024-03-14 17:53:52 +08:00

304 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第一章 绪论
课程地址,[史上最强最细腻的linux嵌入式C语言学习教程【李慧芹老师】_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV18p4y167Md/?spm_id_from=333.999.0.0&vd_source=4e03f52e94cfa281cde032856b1f93a7)。
## 第一节
### C语言发展史
| 时间 | 发展 |
| ---- | -------------------- |
| 1960 | 原型A语言->ALGOL语言 |
| 1963 | CPL语言 |
| 1967 | BCPL |
| 1967 | B语言 |
| 1973 | C语言 |
### C语言特点
1. 基础性语言
2. 语法间接、紧凑、方便、灵活
3. 运算符,数据结构丰富
4. 结构化,模块化编程
5. 移植性好,执行效率高
6. 允许直接对硬件操作
### C语言学习建议
1. 概念的正确性
2. 动手能力
3. 阅读优秀的程序段
4. 大量练习,面试题
### 课程思路
1. 基础概念
2. 数据类型,运算符和表达式
3. 输入输出专题
4. 流程控制
5. 数组
6. 指针
7. 函数
8. 构造类型
9. 动态内存管理
10. 调试工具gdbmake)
11. 常用库函数
### 课程平台
* 老师64位的`redhat6``vim``gcc4.4.6(make)`
* 本人:`WSL-Ubuntu22.04``vscode(remote ssh)``gcc11.4.0(make)``ohmyzsh(theme:eastwood)`
我的`gcc`版本比较新所以很多提示比较完善老师这个课程是很早的课那个时候的gcc提示没有现在厉害所以还是要结合老师的视频的思路在当时提示不完善的时候是如何手撕代码分析出来的。
## 第二节
### 神一般的`Hello world!`
```c
//hello.c
#include <stdio.h>
#include <stdlib.h>
#if 0
void main(void);
void main(int argc, char **argv);// char *argv[]
int main(int argc, char **argv);
int main(void);
#endif
int main(void)
{
printf("Hello world!\n");
exit(0);
}
```
用那种`main`得看编译器环境,目前在`linux``gcc`下,`int main(void);`常用,需要传参用`int main(int argc, char **argv);`
### 源文件到可执行文件
#### gcc
C源文件=>预处理=>编译=>汇编=>链接=>可执行文件
> 所有`#`后面的代码都在预处理解决
```bash
# 单步执行
gcc -E hello.c > hello.i # 预处理生成hello.i
gcc -S hello.i # 编译生成hello.s
gcc -c hello.s # 汇编生成hello.o
gcc hello.o -o hello # 链接生成hello
./hello # 运行
Hello world!
# 一次到位
gcc hello.c # 得到a.out可执行文件
# 指定名字
gcc hello.c -o myhello # 得到myhello可执行文件
```
#### make
```bash
$ make hello
cc hello.c -o hello
# cc就是make选择的编译器这里是gcc
$ ls
hello hello.c
```
### vim
老师对于常用的`.vimrc`做了一些介绍,笔者建议`vscode``remote-ssh`插件可以在win的vscode编辑器享受linux的环境。
## 第三节
### 基本概念
#### 以`Hello world`为例对写程序的思路提出如下要求
##### 1. 头文件正确包含的重要性
```c
#include <stdio.h>
int main(void)
{
int *p = NULL;
int i;
p = malloc(sizeof(int));
if (p == NULL)
return -1;
printf("Hello world!\n");
return 0;
}
```
这里我的gcc版本比较新所以和老师的不一致总之老师的意思就是
> 不要忽略gcc的警告
```bash
# 通过 -Wall 参数让gcc显示全部警告
# 注意'W'要大写
$ gcc hello.c -Wall
hello.c: In function main:
hello.c:7:9: warning: implicit declaration of function malloc [-Wimplicit-function-declaration]
7 | p = malloc(sizeof(int));
| ^~~~~~
hello.c:2:1: note: include <stdlib.h> or provide a declaration of malloc
1 | #include <stdio.h>
+++ |+#include <stdlib.h>
2 |
hello.c:7:9: warning: incompatible implicit declaration of built-in function malloc [-Wbuiltin-declaration-mismatch]
7 | p = malloc(sizeof(int));
| ^~~~~~
hello.c:7:9: note: include <stdlib.h> or provide a declaration of malloc
hello.c:6:9: warning: unused variable i [-Wunused-variable]
6 | int i;
| ^
```
* 例如说这个变量`i`定义了但是没用上,就是你清楚来龙去脉可以忽略的警告。
*`malloc`那个警告就是在告诉你`malloc`所属的`stdlib.h`库未引入。
* C语言程序往往如果能把警告都消除错误也能解决。例如
```c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
FILE *fp;
fp = fopen("tmp", "r");
if (fp == NULL)
{
fprintf(stderr, "fopen():%s\n", strerror(errno));
exit(1);
}
puts("ok!");
exit(0);
}
```
这个程序运行报段错误,这个时候,查看一下警告就是问题所在。
```bash
$ ./a
[1] 1960 segmentation fault ./a
$ gcc a.c -Wall
a.c: In function main:
a.c:12:41: warning: implicit declaration of function strerror; did you mean perror? [-Wimplicit-function-declaration]
12 | fprintf(stderr, "fopen():%s\n", strerror(errno));
| ^~~~~~~~
| perror
a.c:12:35: warning: format %s expects argument of type char *, but argument 3 has type int [-Wformat=]
12 | fprintf(stderr, "fopen():%s\n", strerror(errno));
| ~^ ~~~~~~~~~~~~~~~
| | |
| | int
| char *
| %d
```
`%s`需要的类型是`char *`,但是`strerror(errno)`的类型是`int`,它是所以是`int`是因为C语言对没有找到原型的函数返回值都是`int`,所以根源在于`strerror`函数没有原型,没有引入需要的`string.h`库。加入这个库重新运行。
```bash
[main][~/LinuxC/Chapter1/Section3]$ make a
cc a.c -o a
[main][~/LinuxC/Chapter1/Section3]$ ./a
fopen():No such file or directory
```
##### 2. 以函数为单位来进行程序编写
main`是特殊的定义,其实就是一个正在运行的线程。其实对于内核而言,是只有进程的概念,且与我们理解的进程、线程不一样。
##### 3. 声明部分+实现部分
早期的编译器要求变量先定义后使用。
##### 4. `return 0/exit(0)`
结束当前进程,是给父进程看的。
对于带有`return 0`的程序:
```bash
[main][~/LinuxC/Chapter1/Section3]$ ./hello
Hello world!
[main][~/LinuxC/Chapter1/Section3]$ echo $?
0
```
如果不带`return 0`
老师演示的返回值是13是`printf`的返回的`Hello world!\n`的长度。
在我本地无法复现,新版本可能改了。
##### 5. 多用空格空行
##### 6. 添加注释
```c
//单行注释
/*
* 多行注释
* 多行注释
* 多行注释
*/
//大段的注释
#if 0
func(){
}
#endif
```
#### 算法
解决问题的方法。流程图NS图FSM有限状态机
#### 程序
用某种语言实现算法
#### 进程
#### 防止写越界,防止内存泄漏,谁打开谁关闭,谁申请谁释放