《C语言编程魔法书:基于C11标准》——1.2 用C语言编程的基本注意事项

简介:

本节书摘来自华章计算机《C语言编程魔法书:基于C11标准》一书中的第1章,第1.2节,作者 陈轶,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

1.2 用C语言编程的基本注意事项

C语言的发明其实基于Unix操作系统。当时在C语言未面世之前,Dennis Ritchie所在的AT&T贝尔实验室用的Unix系统是完全用汇编语言写的。汇编语言的优势是直接面向处理器本身,能直接对底层硬件进行控制,充分发挥处理器的硬件能力。然而,它的缺陷也是显而易见的。

1.汇编语言的不足

首先,不可移植性。每种处理器,其指令集都大相径庭,比如ARM有ARM的指令集架构(ISA),Intel x86有x86的ISA,还有MIPS、Power(原来为PowerPC),Motorola 68000等;再加上各类微控制器单元(Micro-Controller Unit,MCU)、各类数字信号处理器(Digital Signal Processor,DSP),每种ISA都有其相应的汇编语言。那么多处理器如果对每一种都使用不同的汇编语言来实现同一个操作系统,那操作系统的开发人员真要崩溃了……而且即便实现出来,可能各个处理器上的实现也会有所不同,标准也很难被统一起来。

其次,汇编语言本身要比高级语言精密。因为汇编语言面对的都是寄存器、存储器以及各类底层硬件,而不是一种抽象的数据模型,所以代码编写时需要非常谨慎,而且调试程序也十分麻烦,且非常容易出错。所以,如果有一种既能面向底层硬件,又能对数据以及程序进行抽象的高级语言出现,那势必既能不太影响程序执行效率,又能大大提升程序的可执行性、可读性以及编写的效率,这将是非常伟大的贡献。C语言也就是在这种背景下诞生的。

如果说,汇编语言面向的是底层硬件、一种过程化的编程风格的话,那么C语言就是面向数据流和算法、一种结构化的编程风格。C语言是一种结构化的、静态类型的编译型编程语言。也就是说,用C语言编写了源代码之后,需要通过C语言编译器进行编译,构建为相应的处理器能直接执行的机器码,然后处理器可以对生成出来的机器码进行执行。所以在各个处理器上,处理器厂商或第三方只需要为当前处理器写一个对应的C语言编译器即可。然后任何符合C语言标准的程序都能在上面编译后执行,除了需要支持某些机器特定的功能和特性外(后面会介绍)。

2.C语言编写程序要注意什么

那么我们在用C语言写程序的时候应该注意哪些方面呢?

1)可移植性:C语言被设计出来的一大初衷就是为了能将同一个源代码放到各个不同的平台上编译运行。因此,如果我们的代码要在多种不同架构的处理器上运行的话,我们就得注意C语言标准规定了哪些特性是编译器必须遵守的,哪些特性是平台或编译器自己实现的。我们要尽量使用标准中已明文规定的编程规范,尽可能避免在不同平台可能会产生不同行为的语法特性。当然,由于上面提到的处理器种类太过多样,尤其在嵌入式开发领域,很多MCU用的还都是8位处理器,这种情况下C源代码就很难被移植到32位或64位系统下了。本书后面将会指出大部分主流平台对C语言标准中所提到的“实现定义”行为的区别。另外,也会提到一些技巧来应对不同的平台
特性。

2)可维护性:可维护性在实际工程项目的研发中非常重要。它体现在最初工程架构的设计、对各个功能模块的划分、相应的开发人员安排,还有后期的测试。一般来说,现在一个工程如果是从无到有进行开发的话会采用螺旋式开发模型。也就是说,一个项目启动后,可以先做一个功能简单但能正常工作的产品原型。然后在此基础上不断地为它增加更多功能,或对之前的功能进行修改。在此期间,我们如何对整个工程进行模块化划分,从而能安排不同开发人员针对不同功能模块进行开发就变得尤为重要。另外,在工程开发过程中,如果有人员流动,那么如何将即将离职的开发人员手中的工作交付给新人也关系到整个项目的进展。因此,一个良好的C语言代码应该具有可读性、良好的文档化注释风格,以及较详细的设计文档。对于一个较大的工程项目来说,开发人员不仅仅需要把自己的代码写好,而且要写得能让别人看懂,并且要做好详细的设计文档,这样才能把项目风险降低。

3)可延展性:大家或许已经知道,像微软的Windows操作系统由数千名工程师合作研发;Linux操作系统对外开源,参与其中的研发人员也有数百上千人。如果我们在一个开发团队中负责一个需要由多人合作开发的工程项目,那么我们写的功能模块需要与其他人写的功能模块进行对接。所以,我们在开发一个较大工程项目时,需要协调好各自对外的模块接口(Application Program Interface,API)。由于C语言没有全局名字空间(namespace)这个概念,所以命名一个对外接口也是非常重要的,否则可能会与其他功能模块的接口名发生冲突。本书后面会对C语言函数命名以及符号连接做进一步介绍。

4)性能:性能是提升程序使用者效率和生产力的体现。一个应用程序的性能越高,那么计算一个任务所花费的时间越短,也越节省计算机的耗电。而对于如何提升性能,一方面需要程序员对处理器架构、硬件特性有一定了解;另一方面需要程序员拥有比较丰富的算法知识,能针对实际需求灵活采用高效的算法。而像C语言这种十分接近硬件底层的高级编程语言,能极大限度地发挥处理器的特长,从而达到高效的运行性能。

相关文章
|
存储 编译器 C语言
【C语言】数据类型全解析:编程效率提升的秘诀
在C语言中,合理选择和使用数据类型是编程的关键。通过深入理解基本数据类型和派生数据类型,掌握类型限定符和扩展技巧,可以编写出高效、稳定、可维护的代码。无论是在普通应用还是嵌入式系统中,数据类型的合理使用都能显著提升程序的性能和可靠性。
570 8
|
C语言 开发者
C语言中的模块化编程思想,介绍了模块化编程的概念、实现方式及其优势,强调了合理划分模块、明确接口、保持独立性和内聚性的实践技巧
本文深入探讨了C语言中的模块化编程思想,介绍了模块化编程的概念、实现方式及其优势,强调了合理划分模块、明确接口、保持独立性和内聚性的实践技巧,并通过案例分析展示了其应用,展望了未来的发展趋势,旨在帮助读者提升程序质量和开发效率。
688 5
|
C语言
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性。本文探讨了C语言中的错误类型(如语法错误、运行时错误)、基本处理方法(如返回值、全局变量、自定义异常处理)、常见策略(如检查返回值、设置标志位、记录错误信息)及错误处理函数(如perror、strerror)。强调了不忽略错误、保持处理一致性及避免过度处理的重要性,并通过文件操作和网络编程实例展示了错误处理的应用。
404 4
|
存储 算法 C语言
C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项
本文深入探讨了C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项,并通过案例分析展示了实际应用,旨在帮助读者提高编程效率和代码质量。
723 4
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
780 3
|
程序员 编译器 C语言
C语言中的预处理器指令,涵盖其基本概念、常见指令(如`#define`、`#include`、条件编译指令等)、使用技巧及注意事项
本文深入解析C语言中的预处理器指令,涵盖其基本概念、常见指令(如`#define`、`#include`、条件编译指令等)、使用技巧及注意事项,并通过实际案例分析,展示预处理器指令在代码编写与处理中的重要性和灵活性。
592 2
|
NoSQL C语言 索引
十二个C语言新手编程时常犯的错误及解决方式
C语言初学者常遇错误包括语法错误、未初始化变量、数组越界、指针错误、函数声明与定义不匹配、忘记包含头文件、格式化字符串错误、忘记返回值、内存泄漏、逻辑错误、字符串未正确终止及递归无退出条件。解决方法涉及仔细检查代码、初始化变量、确保索引有效、正确使用指针与格式化字符串、包含必要头文件、使用调试工具跟踪逻辑、避免内存泄漏及确保递归有基准情况。利用调试器、编写注释及查阅资料也有助于提高编程效率。避免这些错误可使代码更稳定、高效。
1947 12
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
消息中间件 Unix Linux
C语言 多进程编程(五)消息队列
本文介绍了Linux系统中多进程通信之消息队列的使用方法。首先通过`ftok()`函数生成消息队列的唯一ID,然后使用`msgget()`创建消息队列,并通过`msgctl()`进行操作,如删除队列。接着,通过`msgsnd()`函数发送消息到消息队列,使用`msgrcv()`函数从队列中接收消息。文章提供了详细的函数原型、参数说明及示例代码,帮助读者理解和应用消息队列进行进程间通信。