2.0 C语言开发环境搭建

  1. Visual studio(全宇宙最强IDE)

记得勾选C++就可以

2.1 C语言常用命令

Dir:列出当前目录下的文件以及文件卷
md:创建目录
rd :删除目录
cd:进入指定目录
cd..:退回上一级目录
cd/:退回根目录
del:删除文件
exit:退出DOS
cl:编译和链接
注意要点:

  1. 使用Visual studio自带编译器执行

  2. 不在同一盘符内不可执行需要进入到程序所在盘符(不用CD)

  3. 进入盘符之后需要CD进入文件卷,进入文件卷之后再CI编译和链接

  4. 注意指令间的空格

    2.1.1 练习:使用命令行生成一个关机程序

    #include <stdlib.h>
    void main () {
    system("shutdown -s -t 600");
    }

    编译:cl .c
    生成取消程序
    Main函数是主要程序,项目中必须有,仅只允许有一个,它是一个程序的入口。

    2.2.1 system(“pause”)和getchar()的区别

    相同点:两者都是让程序暂停
    区别:

  5. getchar(); 读取一个字符

  6. System(“pause”);既让操作系统来暂停该程序的执行,同时程序运行到此语句时,会让程序的窗口上显示”Press any key to continue…” 也就是”按任意键继续“,即等待的用户按下任意键使得该程序从暂停状态返回到执行状态继续从刚才暂停的地方开始执行。

    2.3.1 #include 说明

    Include 包含我们需要的函数定义。
    windows系统预制了很多库函数,我们需要采用就需要用#include去调用这些。
    源代码最终是需要被编译器处理的。编译器编译的过程比较复杂,但一般需要经历好几步。第一步是预处理。所谓预处理,就是编译前,先进行些预先的处理,如代替源代码中需要代替的部分。#include 就是这么一个预处理指示指令。

    #include 是C语言预处理器标识符。#和include之间可以有多个空格。#也不一定要顶格,但是一定是第一个非空白字符。#include的作用,是告诉编译器在编译前,要做一些预先处理:将后面<>中的文件内容包含到当前文件内,所谓包含,是指将<>中列出的文件的内容复制到当前文件里。

    注意:#一定要是第一个非空白字符。否则编译器会提示错误,并且错误信息和出错原因完全不匹配。
    因为getchar 和 printf 两个函数的声明位于 Stdio.h 文件中,所以简单的用#include把stdio.h文件包含进来,自然就把1getchar 和 printf 两个函数的声明包含进来了。
    说明:函数声明只是向编译器登记有这么一个函数,声明了函数不调用这个函数,是被允许的。这也就是为什么包含了整个stdio.h文件,里面声明了很多其他函数,但实际没有使用这些函数而编译器又不提示的原因。

    2.4.1 BUG的意思

    Bug的英文意思是臭虫,被引入到计算机领域,需要追溯到第一代计算机时代。当时的计算机是由许多真空管构成,需要利用大量的电力使真空管发光。某天,一只虫子爬进了其中的某只真空管中,计算机于是停止工作了。研究人员耗费了很长时间,找来找去,一处地方一处地方排查,终于发现这个虫子,取出虫子后,计算机就恢复了正常,于是BUG这个词语就在计算机领域中代表了隐藏的错误、缺陷、漏洞或者问题。把排除错误的过程称为DeBug。

    2.4.2 断点调试

    断电是为了方便程序员在调试过程中观察程序内部各状态而专门设置的一种调试手段。也就是在调试模式下运行程序过程中,当程序语句运行到设置断点后,暂停程序运行,但是程序当时的内存,寄存器,上下文环境等数据都被保持,并且在源码编辑器中指示出当前停留在代码的哪一行。然后程序员就可以不慌不忙利用调试器查看程序内部状态。

    2.4.3 C语言程序编译过程

    预处理:

    预处理就过程实际上是处理”#”,将include包含的头文件直接拷贝到hell.c当中;将#define 定义的宏进行替换,同时将代码中没用的注释部分删除等
    具体做的事情如下:

  7. 将所有的#define 删除,并且展开所有的宏定义。说白了就是字符替换

  8. 处理所有的条件编译指令。#ifdef #idndf #endif等,就是带#的那些

  9. 处理#include,将#include指向的文件插入该行出

  10. 删除所有注释

  11. 添加行号和文件标识,这样的在调试和编译出错的时候才知道是哪一个文件的哪一行。

  12. 保留#pragma 编译器指令,因为编译器需要使用它们。

    编译:

    编译的过程实质上是把高级语言翻译为机器语言,即对a.c做了这些事情。

  13. 词法分析

  14. 语法分析

  15. 语义分析

  16. 优化后生成相应的汇编代码

从高级语言到汇编语言再到机器码
Gcc -s hello.c -o a.s 可以生成汇编代码
Gcc -c hello.c -o a.o 可以将源文件翻译成二进制文件。类Uinx系统编译的结果生成.o文件,Windows系统是生成.obj文件。
编译的过程就是把hello.c翻译成二进制文件

链接

就像刚才的hello.c它使用到了C标准库的东西”printf”,但是编译过程只是把源文件翻译成二进制而已,这个二进制还不能直接执行,这个时候就需要做一个动作,将翻译成二进制与需要用到的库绑定在一起。举个例子编译过的过程就是比如人要打你,你打电话叫人。你的人还没到就跟人打,这肯定被人打的惨不忍睹,肯定是你的人到了才打比较保险。

Gcc hello.c -o a 可以生成可执行程序。即Gcc不带任何参数。ldd就可以看到你的可执行程序依赖的库。

可以看到a.o的大小是1.1k,毕竟它只是把源文件翻译成二进制文件。a却有7k,应该是他多了很多绳子,在运行时候这些绳子就将对应的库函数牵过来。很形象的比喻。

2.4.4 C语言程序结构

  1. 一个程序由一个或多个源文件组成

预处理指令例如包含头文件
全局声明 在函数之外进行的数据声明
函数定义 函数用来实现的功能

  1. 函数是C程序的主要组成部分

必须包含一个Main函数(只能有一个)
每个函数都用来实现若干特定功能
被调用的函数可以是库函数,也可以是自己编制设计的函数
程序总是从main函数开始执行

  1. C程序对计算机的操作由C语句完成

C程序书写格式是比较自由的,一行可以几个语句,便于阅读只写一行
数据声明和语句最后必须有分号
C语言本身不提供输入输出语句
程序应当包含注释,增加可读性