老汤回味——C语言基本介绍

在软件世界,有很多东西像陈年老酒一样,时间越久越香醇,C语言就是其中之一。C语言伴随着UNIX系统而产生,却一直居于编程语言排行榜前列,最近几个月的TIOBE编程语言排行榜,C语言的涨幅惊人,再一次焕发了活力。


C语言在现阶段,主要用于操作系统和嵌入式系统开发中,物联网行业大量硬件设备的对接,也需要C语言的参与,这也是C语言复苏的原因之一。C语言语法轻巧简洁,但是和硬件有很好的亲和力。


自己以前一直在使用C语言,个人感觉,学好C语言,入门其他语言的门槛将会大幅降低,这里的学好,不只是会用C语言写程序,还包括使用C语言写出结构良好的代码,充分利用C语言的语法写出具有面向对象思想的代码(这一点Linux内核做到了),考虑到这些,决定回味一下C语言,后面的几篇文章可能都会围绕C语言展开。


编程领域存在很多思想,编程语言是我们的工具,而理解语法及其使用场景是我们用好工具的前提,所以,任何语言没有学好,就试图用这种语言进行开发,往往是很危险的,很有可能会掉入陷阱。C语言更是如此,C语言语法简洁灵活,所以可以用C语言实现任何可能的事情,但同时,C语言很底层,有不少陷阱,灵活的使用也经常使得代码失控。可以这样说,C语言就是降龙十八掌的招式,招式虽然不多,但是足够强大,如果再具备强劲的内功,那就是天下无敌。


闲话少叙,开始主题,我们从C语言的Hello World走起,下面的介绍主要针对在Linux下的开发,Windows下可以使用VS,MAC可以使用xcode,代码使用的是标准的C语言语法和库,创建hello_world.c文件,输入以下内容:

#include <stdio.h>

int main(void) {
    printf("Hello World!\n");
    return 0;
}

对上面的代码进行说明:

  1. #开头的语句,是C语言的预处理指令,#include是引入其他文件,可以简单的理解为将头文件stdio.h的内容填充到这个位置,stdio.h中是标准io函数的声明;

  2. main函数是程序的入口点,返回整型,参数是void,说明不需要传入参数;

  3. printf是stdio.h中声明的函数,用来在标准输出输出字符串;

  4. return用来返回值,C语言建议main应当返回值,返回0代表正常退出,返回其他非0值,通常代表执行出错。


以上就是一个简单的C语言编写的.c文件,但是这样的文件还不能执行,需要对其进行编译。关于C语言的编译步骤,可以分解为四个步骤:预处理,编译,汇编和链接。预处理阶段就是处理预处理指令,为编译做准备;编译阶段检查语法错误,同时将程序翻译为汇编语言代码,不同的处理器架构,有不同的汇编指令集,这也就是为什么不同的处理器架构使用不同的C语言编译器的原因;汇编阶段将汇编指令转变为二进制目标代码;最后链接阶段会将用到的相关的二进制代码集中在一起,比如我们上面用到printf函数。


下面我们就使用gcc进行编译:


gcc -E hello_world.c -o hello_world.i

预处理,生成.i文件


gcc -S hello_world.i -o hello_world.s

编译,生成.s汇编文件


gcc -c hello_world.s -o hello_world.o

汇编,生成.o二进制文件


gcc hello_world.o -o hello_world

链接,生成可执行文件hello_world


上面的前几个步骤可以直接跨越过去,只需要一条命令即可:

gcc -o hello_world hello_world.c


这样,在命令行输入

./hello_world


输出:

Hello World!


我们看到了第一个可执行程序,接下来我们做一些分解,使得我们的代码更像一个C语言项目,我们会定义三个文件:

hello.h:hello库的头文件;

hello.c:hello库的源文件;

main.c:main函数的文件。


hello.h内容如下,其中包含了print_hello_world函数的声明,声明的作用就是告诉使用者,我们有这样一个函数可以给你调用:

#ifndef HELLO_H
#define HELLO_H

void print_hello_world();

#endif

这里是print_hello_world函数的定义,首先,我们需要引用stdio.h头文件,因为我们要使用其中的printf函数。


使用hello.h和hello.c编译动态链接库libhello.so:

gcc hello.c -fPIC -shared -o libhello.so


编译静态链接库libhello.a:

gcc -c hello.c

ar -crv libhello.a hello.o


动态链接库在运行时加载,静态链接库在编译阶段会被编译进可执行文件,带来最直观差别,就是生成的可执行文件大小会不同,当然运行阶段,静态链接库会快一些。


编写main.c函数,调用print_hello_world函数:

#include "hello.h"

int main(void) {
    print_hello_world();
    return 0;

}

使用动态链接库编译:

gcc main.c -L. -lhello -o main_shared

$ ls -al main_shared

-rwxr-xr-x 1 yjp yjp 8288 5月  12 11:06 main_shared


使用静态链接库编译:

gcc main.c -L. -lhello -static -o main_static

$ ls -al main_static

-rwxr-xr-x 1 yjp yjp 844768 5月  12 11:08 main_static


可见两个文件大小差别很大,下面运行一下,./main_static可以直接运行,对于动态链接,运行时查找,需要通过环境变量添加库搜索路径:

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

$ ./main_shared

Hello World!


今天的文章牵扯的概念比较多,这也正是C语言底层和灵活的体现。


猜你喜欢

转载自blog.csdn.net/yjp19871013/article/details/80289973
今日推荐