本系列博文,重在以最基础,最简单的思想帮助初学者能够更直观地学习一门语言,这里当然是以C语言为例,作为最广泛,实用的语言,虽然不像其他语言功能强大,但是C语言的知识涵盖的思想是最全面的,而且它能操控指针的思想则是更能让我们去发掘那些存在于我们思维空缺的疑问。所以博文的内容可能是最基础的东西,我想以一个初学者的角度方式,去理解C语言的每一个语法,定义,包括其中的内存原理思想,代码架构。当然本人也才是学习C语言1年之久,本着大家相互学习,分享,共同发展的想法,在这里给大家分享一些我在代码学习的过程中所感受到的代码思想!
每个人学习一门编程语言,都免不了与一个叫helloworld的程序打交道!
2
3
4
5
6
|
#include
int
main()
{
printf
(
"Hello, World!"
);
return
0;
}
|
当然,每一个初学者使用的工具可能都不一样,比如Mcrosoft Visual C++ 、Microsoft Visual Studio、C-Free,Dev-C++等开发工具,这里我们将不以这些工具的使用为基础进行讲解,而是深入分析在这些琳琅满目的工具下对于c语言开发所共通的一些基础知识。本文将以下图为基础流程对helloworld程序进行分析解读;
1,编译环境
编译环境就好像一个解释器一样,无论如何定义他的名字,他都是我们书写的代码与系统之间的桥梁,对于各种c语言开发工具在其安装的过程中会默认的帮我们搭配好编译环境,即使我们没有刻意的去注意它的存在。对于c语言中使用的各种你所学到的c语言语法知识,定义,它都能解析得到并转化为机器能识别的语言,从而能运行在你所使用的机器上面。简而言之,一个编写好的c程序代码,之所以能在各种不同的系统上运行,在于编译环境的完美适配。也就是说,编译器的开发公司会去考虑针对每个系统开发不同的编译器,而我们所需要做的只是对于各个系统下载对于的编译器即可。而开发层面上的东西就不会在因为操作系统的不同而异了,
2,它是个文件
无论哪种语言,无论哪种开发工具,当你开始书写代码的时候,它总是会帮你创建一个文件,或者是你自己手动创建一个文件或者多个文件,。以helloworld为例,都会创建一个“helloworld.c”的文档文件,既然是文档文件,他就有属于它的编码格式。比如ASCII,Unicode,UTF-8,GB2312等等,具体是哪一种编码格式,其实我们都不用管,这是你创建这个文档文件所使用的工具决定的,当然你也可以设置,因为编译器都能识别的到并正确的解析出来。为什么会是文档,因为代码是我们人书写的啊,至少我们自己要能看得懂啊,哈哈。于是我们按照已有的c语言知识书写了如上代码块,简简单单的6行代码。’
3,编译过程
当你的代码书写完毕后,保存文件,之后的过程就是编译了。对于各种开发工具,都有一键编译,运行的按钮,这些都是工具已经帮你封装好了编译过程,对于命令提示符(cmd),linux命令行之类的开发方式,可能你会跟清晰地了解到编译过程,这里将重点讲解编译过程,因为这是一门语言最为关键的一步,也是它的根基所在。当然,我在这里的理解完全来自于我个人的看法,思路,本人对于数据结构,编译原理这一块的知识也是相知甚少,所有重在理解编译器的一种思想。或者说当开发者设计这种语言的时候,无论他是通过怎样的定义,逻辑,去完善C语言编译器,都离不开一些基础的理解,编译步骤的具体步骤,其实都是开发者一步一步的完善,整理才有了我们现在看到的强大的语言。
最开始当你点击编译按钮,或是在终端输入“gcc helloworld.c -o helloworld”,代码的编译过程就开始了,考虑电脑只是执行者,不是主导者,它必须要知道我们人类输入的代码在哪里,它要编译的文件是哪一个,很明显,要么是编译工具中你打开的文件,要么是gcc命令后面跟上的参数,针对这条命令来说明输入的内容:
gcc是一个可执行的文件,一般说的命令其实都是一个可执行的程序,系统会在它记录的文件目录下去找你输入的命名同名的可执行文件,而这些文件目录是系统环境变量,其实之前配置环境变量就是这个意思,让系统记录下你的编译器程序所在的目录,然后你的gcc编译器的gcc命令就可以使用了,其实如果你没有配置好环境变量,但是编译器你安装好了,也可以通过输入“目录/gcc helloworld.c -o helloworld” 也可以运行编译,前提是你要知道gcc的目录。之后其他的一系列的编译过程都是gcc所控制的。
“helloworld.c”这个字符串属于gcc 的第一个参数,也是我们给编译器指明的编译文件,这个参数也可以是多个,这里只讨论一个文件,其后缀".c"也不是必然的,只是我们默认一个c语言编写的文档文件最好被命名为“*.c”,这样gcc就知道了它所要编译的代码块在哪里了。
“-o helloworld” 这一个字符串是可选择的,表示最后编译出来的可执行文件命名为helloworld。就算你不加这一个参数,gcc也会编译出一个默认名字的可执行文件"a.out”,这个可执行文件就算是当前操作系统可以运行的程序了,就相当于与gcc一样它也是一个程序。而这个可执行文件的产生也就是编程工具点击“编译”按钮的全过程了,只是这整个过程都帮我们包装好了,但底下的运行过程都是一样的。
接下来说说我对编译器编译一块代码的理解吧。针对“helloworld.c”这个程序:
1,以c语言的语法是以“;”为一句代码的结尾说明,而在一句代码的上面还有其他的语句,这其他的语句都是以文档的一行为识别标志;也就是说编译器会以一行为终结点去解析代码,所以解析开始时第一句代码就是“#include
2,第二行“int
main()
”,这里又有一个关键字“main”,是一个函数 名,这个也是必须要有,并实现的函数,因为在可执行文件里,代码运行的第一个指针,就是从main函数开始的,没有的话就会报错。这个函数的参数,返回值好像不是固定的,但也要符合某些默认的方式,至少它是一个函数,要符合函数的书写方式。函数的定义就是现代语言比较普遍,精髓的地方了,它就像在代码运行的过程中设立了一个又一个的房间,每个房间有着特殊的环境,函数的入口,出口都通过特定的方式。这里关于函数的优势暂时不讨论,只要按照函数的方式书写,并且函数名为main,编译器就会以特殊的方式去解析这个函数,或者说给这个函数设置一个标记位,说明他是一个“main函数”。这里编译器就会把main后面{}所包含的代码块标记为main函数的代码,具体怎样的实现方式我也不得而知,但是重在理解他的思想,其实仔细去看也并没有那么复杂。当然,他在解析函数的模式时,也是一行一行的解析过来的,不会跳跃式的解析,类似于堆栈的思想。
3,第三行“{”,是属于main函数模式中的一块,当解析到这一行,会被编译器语法认定为是main函数函数体的开始,因为前面有识别到函数的书写方式。如果编译器解析到这来不知道它属于谁的模式的一部分,那可能就会报错,从而编译不过。
4,第四行“printf
(
"Hello, World!"
);
”到这一行,以下的部分都被设置为main函数的主体部分了,这一行属于调用了一个函数,函数调用的书写方式一般都是“函数名(参数)”。关于函数的写法就按照书本上的去学习,这里我们尝试的去理解函数printf的功能;
5,第五行“return
0;
”这个属于函数的一部分,也是函数运行的出口,当然如果没有这一句,函数会把代码块的最后当做出口,这个“return”也属于一个关键字,它的使用方式也有着一定模式;它说明了函数最后出口所能呈现的类型以及值。具体意义以后再做讨论。
6,第六行“}”是属于main函数模式中的一块,当解析到这一行,会被编译器语法认定为是main函数函数体的结束,因为前面有识别到函数的书写方式。如果编译器解析到这来不知道它属于谁的模式的一部分,那可能就会报错,从而编译不过。
编译的最后,编译器识别到文件的结尾,暗示着这一次的代码解析就结束了,之后就是如何将这些代码转换为系统能够运行的文件模式了,当然这些我们将在以后的博客文章中去了解。