计算机中 C 语言的应用特点分析

韩润华 丁颖
(西安明德理工学院,陕西西安 710124)

摘要:本文从实际开发场景出发,分析 C 语言在系统编程、硬件操作及跨平台开发中的核心应用特点,探讨其“高效性”“底层控制力”与“灵活性”三大特性,结合典型应用案例说明其不可替代性,为开发者选择技术方案提供参考。

关键词:C 语言;应用特点;系统开发

引言:

C 语言从 1972 年创立至今一直是操作系统、嵌入式开发的重要工具,虽然近年来 Python、Java 等高级语言更迅速的流行,但 C 语言在实际一些场合中(尤其是物联网、工业控制等)仍扮演着重要的角色。笔者结合自身开发中的实际案例,论述 C 语言在当今计算机中的应用意义和限度。

一、C 语言在系统开发中的核心地位

1.操作系统开发的基石

作为底层硬件开发语言的首选,C 语言的主要原因是它具有清晰简洁的语法和接近硬件的优势。拿 Linux 操作系统内核为例,该内核中近 80%代码是用 C 语言编写的,例如在进程调度、内存管理等内核模块,都是通过 C 语言对硬件内存和寄存器进行直接操作的。而在硬件或设备驱动开发时,开发者也可根据自身经验通过 C 语言中的指针直接操作 GPIO(GeneralPurposeInputOutput)口,例如树莓派在进行项目开发时,只需几行代码就可控制外接传感器高低电平信息,使其驱动 LED 灯的亮与灭或者获取温度信息。C 语言这 一 特 性 对 操 作 系 统 等 对 时 间 精 度 有 要 求 的 系 统(RealtimeOS)来说必不可少。然而,高级语言(如Python或 Java)运行于虚拟机或解释器内部,无法绕过中间环节直接对硬件进行操作,更像一把“电钻”,只有在必要的情况下,开发者才能够发挥其“螺丝刀”的作用,“拧紧”每一个系统部分。

2.硬件资源的高效管理

C 语言的指针内存分配和释放(malloc 和 free)尽管古老、笨拙和直接,却适用于那些非常珍惜内存的嵌入式程序开发。很多实时性的工业控制器,在不考虑暂停的自动垃圾回收机时,会导致系统控制器的响应偏差(譬如,机械臂的运动控制指令,Java 语言运行着不可预料的时间),而利用C 语言人工控制分配和释放内存空间,可以保证诸如工业机器人运动控制等必须任务的毫秒响应。在工业机器人上利用C 语言实现内存池的方式就是预先分配出一大块连续内存,进行固定大小的循环分配,而不必担心内存的碎片化。

另外,C 语言的位运算、结构体内存对齐功能等都可以通过指令完成对内存的管理,做到更为高效的存储。在某些单片机系统内,开发人员还可以利用位域(bit-field)将一组状态变量压缩进一个字节,节省嵌入系统的昂贵硬件。这就是指针内存分配所控制的所谓“能不花钱就不花,能少花钱就少花”的原则。

3.开发工具链的成熟生态

C 语言经过近 30 年的成熟,拥有了工具生态。GCC 编译器能够编译 x86 服务器和 ARM 嵌入式芯片之间的底层程序,一个源文件,只需改变编译器指令编译到另一台机器上,只需更改命令行参数即可;GDB 用来调试系统底层核心模块的系统崩溃问题,例如 Linux 内核态设备驱动模块的空指针异常现象;Valgrind 用来检查应用程序内存泄露情况,并支持在代码中标识各种内存操作,以改进代码性能;SQLite数据库的核心源代码使用纯 C 编写,通过 C 语言#ifdef 和#endif 的支持,实现了在不同环境间(Windows、Linux 和MacOS)的适配;Python 语言对底层文件读写的封装也使用了C 语言封装,如 cPickle。这些应用工具的描述可以让我们看出 C 语言并非孤军奋战,而是借助丰富的生态接口和应用得以不断支持着底层的开发及维护。

二、C 语言在跨平台开发中的灵活性与局限性

1.可移植性的双刃剑特性

跨平台性的先天支持离不开 C 语言,那便是以 ANSI 标准为基础制定的统一的语法和一些基本库函数的实现,比如打开文件的库函数 fopen 和写文件的库函数 fwrite,用这两种库函数编写的一段 C 语言程序,可以在 Windows、Linux以及 macOS 等平台上编译,并且输出一致的运行结果。因此很多跨平台工具的开发,都是基于 C 语言来完成的,如FFmpeg 多媒体库,其底层代码都是由 C 语言完成,并且在主流的操作系统上均能够进行编译和运行,跨平台性的优势较为明显。但是硬件级不同所造成的错误容易成为跨平台性的一个陷阱,比如关于字节序方面的问题,采用 ARM 架构设计的嵌入式设备的运行模式都是以小端字节序的方式来保存数据,但是目前对于网络协议的默认定义均为以大端字节序的方式来保存数据,若编程人员在程序设计的过程中,没有特意调用 htonl()以及 ntohl()函数的方式将字节序进行转换,结果可能会导致某温度传感器的采集数据在经过程序转换为整数形式时,出现对传感器读回温度值进行错误转换的问题。

2.系统级接口的适配优势

对于 Windows 系统和 Linux 系统的 API 差异,C 语言的条件编译就是让一行代码不同操作系统的 API 调用“各行其事”,如 Windows 的线程创建方法调用 CreateThread()函数,Linux 使 用 pthread_create() 函 数 , 可 以 在代 码 里 写 入#ifdefWIN32,#ifdefLinux 两种条件分支,自动选取操作系统的相应系统接口,就类似 C 语言程序一样。开源数据库SQLite 正是这种机制的践行者:其提供了预置的包括VxWorks、Android 等多个系统的系统层适配文件,C 代码中编写对应的文件锁实现、内存分配实现,并最终由条件编译选择文件锁和内存实现,最终实现了“一行代码,多平台”。正因为有这种可移植性,所以让 C 语言成为了实现多平台系统工具的语言,如用于处理音视频编解码的 FFmpeg 核心代码也全为 C 语言编译,可以直接应用在 iOS 和 Android 应用上。

三、C 语言在性能优化中的不可替代性

1.执行效率的极致追求

C 语言的灵魂是“低级”。相比于 Python 这样的解释性语言,在解释器或虚拟机的高层中,C 语言将最终的源码直接编译为机器码,不存在一层层的调用开销。以快排算法为例,在 Python 实现中,循环内部是动态解析的循环逻辑,且内含动态类型转换,在 C 语言中静态分配内存地址进行处理,循环内部的指令执行效率能够获得十几倍的增长。对于一个图像实时处理的例子,在树莓派上部署深度学习的人脸检测代码,C 语言基于图像本身的特征算法能够实现实时处理每秒 20 帧以上,而同样的程序在 Python 中可能出现卡顿的情况,或者帧率不足的问题。或者在编译的代码内部直接加入内联汇编,完成特定的代码段优化。

2.实时系统的刚性需求

对实时性有特别要求的应用场景,如工业机器人控制、航空航天等只能选用 C 语言。因为对工业机械臂进行运动路径规划的计算,往往要求每毫秒计算数个坐标值以及驱动电机相应,任何不可预知的延迟都可能导致报废或者人员伤亡。典型的如汽车整车生产线上的焊接机器人,采用 C 语言编写的控制程序对硬串行端口的定时器进行操作,经过调整之后,让机器每隔 0.5 毫秒完成一次闭环控制。然而,Java、Go 等语言由于其垃圾回收机制存在的不可避免的、持续在100~200 微秒级别的延时却无法满足这种需求。自动驾驶则将这种优势变得更加明显,汽车周围散落在空间中的激光雷达可以提供每秒几百万个三维坐标点,C 语言实现的滤波算法使用 C 语言本身直接在内存中连续读写和 DMA (DirectMemoryAccess)绕过 CPU 直接将数据传输的时间降低到纳秒级别。即使被称作下一代内存安全语言的 Rust,在所有者模型的设计上,也引入了额外的判断逻辑来与具体的状态关联,并且不可能说对软件层面的一些计算的不可预料的响应时间,而 C 语言因为直接操作硬件本身的“代码即机器”的透明性,可以被认为“总是”作为实时系统的开发金标准。

3.资源受限环境的生存法则

在每 KB 甚至每字节计算力的年代,C 语言的内存手动管理功能是一种生存技能。在一些用 8 位单片机(一般只有4KB 的内存)实现智能家居温控器的案例中,许多开发者都需要把温度上限、工作模式等 8 个状态打包存储为一个字节,而这在 C 语言里只需一个结构体位宽度定义即可实现,根本不用关心这个打包组合在芯片上的“单位价格”。而 Rust标准库及编译后的代码太大,一个电器的控制(比如一个空调,吹热或冷、除湿或不用)、微控制器芯片、外围电路乃至整个器件都要考虑。比如一款空气净化器的控制单片机,需要考虑并行读取 PM2.5 传感器和风扇的 PWM(脉宽调制)驱动信号,由 C 语言编写的代码中把传感器结果以数据缓冲区形式分配内存,并将指针指向缓冲区内存单元,然后通过指针“搬运”内存到寄存器。总计占用的芯片程序和数据内存不超过 2KB。而 Rust,即使编译链接的时候不链接 std库,也要增加 30%以上的安全检验指令,因为嵌入式内存空间少,凡是写代码都占用内存,即使是像#error 这样简单的指令,也会增加一两行。在这种绝对需求控制资源的时代,C 语言可以继续成为万物互联终端、可穿戴设备等嵌入式领域的主力平台。毕竟在电池容量能提供的最大电流只有毫安级的时候,程序里多余的代码行都可能是扼杀电池续航能力的“罪魁祸首”。

结束语:

作为“底层的语言”,C 语言基于对底层“硬件”贴近的原则,其还在更多系统开发、优化性能的应用中发挥着作用。C 语言对于本就缺少“现代语言”的高级抽象设计,还起到在“需要与底层硬件交互”和“需要最高性能”时做底层的语言的作用。如何运用好 C 语言和其他语言结合解决问题,根据具体情况而言,对于有系统的开发者在系统层使用 C 语言,同时可以将“对上层业务逻辑”的开发者结合自身的业务属性进行分析,使用其他高级语言构建业务逻辑框架,这样可以达到不同的效果。

参考文献:

【1】宁万龙.计算机中 C 语言的应用特点分析[J].造纸装备及材料,2020,49(1):83.

【2】刘鑫茹.对计算机中 C 语言的应用特点的分析[J].轻纺工业与技术,2020,49(1):145-146.

About Author /

Leave a Comment

Your email address will not be published.

Start typing and press Enter to search