文章 答疑

如何成为一名合格的 C/C++ 开发者?

资深开发工程师,CSDN 认证博客技术专家,曾担任多个商业项目的客户端和服务器端主程、架构师。
文章

写在前面的话

在大多数开发或者准开发人员的认识中,C/C++ 是一门非常难的编程语言,很多人知道它的强大,但因为认为“难”造成的恐惧让很多人放弃。

笔者从学生时代开始接触 C/C++,工作以后先后担任过 C++ 客户端和服务器的开发经理并带队开发,至今已经有十多年了。虽然时至今日哪种编程语言对我来说已经不再重要(我目前主要从事 Java 开发),但 C/C++ 仍然是笔者最喜欢的编程语言。在我看来,C/C++ 一旦学成,其妙无穷,就像武侠小说中的“九阳神功”一样,有了这个基础,您可以快速学习任何语言和编程技术。

C/C++ 的当前应用领域

需要注意的是本文不细分 CC++ 的区别,通常情况下,C++ 可以看成是 C 的一个超集,在古典时期,可以认为 C++ 就是 C with classes。虽然如今的 C++ 从功能层面上来看,离 C 越来越远了;但是从语法层面来上来看,大多数 C++ 语法还是与 C 基本一致的——所谓 C++ 的面向对象特性,如果细究 C++ 类方法的具体语法还是 C 的过程式语法。当然,面向对象是一种思想,语言本身对其支持的程度固然重要,能否熟练使用更要看开发者的水平。

C 语言目前主要用于像操作系统一类偏底层的应用开发,包括像 Windows/Linux 这样的大型商业操作系统,以及嵌入式操作系统、嵌入式设备上的应用。还有一些开源的软件,也会选择 C 开发,这些系统主要优先考虑程序执行效率和生成的可执行文件的体积(C 代码生成的可执行文件体积相对更小),当然还有一些是历史技术选型问题,这类软件像 Redis、libevent、Nginx,目前像国内的电信服务商所使用的电话呼叫系统,一般也是基于一款叫 FreeSWITCH 的开源 C 程序做的二次开发(项目地址:https://freeswitch.com/)。

C++ 面向对象的语法与 C 相比较起来,在将高级语言翻译成机器二进制码的时候,C++ 编译器在背后偷偷地做了大量工作,生成了大量的额外机器码,而这种机器码相对于 C 来说不是必须的。例如,对于一个 C++ 类的实例方法,编译器在生成这个方法的机器码时,会将函数的第一个参数设置成对象的 this 指针地址,以此来实现对象与函数的绑定。正因为如此,许多开发者会优化和调整编译器生成的汇编代码。

我们再来说说 C++。C++ 的应用领域目前有三大类,第一类就是我们目前见到的各种桌面应用软件,尤其 Windows 桌面软件,如 QQ、安全类杀毒类软件(如金山的安全卫士,已开源,其代码地址:http://code.ijinshan.com/source/source.html)、各种浏览器等;另外就是一些基础软件和高级语言的运行时环境,如大型数据库软件、Java 虚拟机、C# 的 CLR、Python 编译器和运行时环境等;第三类就是一些业务型应用软件的后台,像游戏的服务器后台,如魔兽世界的服务器(代码地址:https://github.com/azerothcore/azerothcore-wotlk)和一些企业内部的应用系统。笔者在某交易所从事后台开发,其交易系统和行情系统就是基于 C++ 开发的。

C++ 与操作系统平台

从上面的介绍可以看出,与 Java、Python 等语言相比,C/C++ 语言是离操作系统最近的一种高级语言,因此其执行效率也比较高。但是有得必有失,因为如此,C/C++ 这门语言存在如下特点。

C/C++ 整套的语法不具备“功能完备性”,单纯地使用这门语言本身提供的功能无法创建任何有意义的程序,必须借助操作系统的 API 接口函数来达到相应的功能。当然,随着 C++ 语言标准和版本的不断更新升级,这种现状正在改变;而像 Java、Python 这类语言,其自带的 SDK 提供了各种操作系统的功能。

举个例子,C/C++ 语言本身不具备网络通信功能,必须使用操作系统提供的网络通信函数(如 Socket 系列函数);而对于 Java 来说,其 JDK 自带的 java.net 和 java.io 等包则提供了完整的网络通信功能。我在读书的时候常常听人说,QQ、360 安全卫士这类软件是用 C/C++ 开发的,但是当我学完整本 C/C++ 教材以后,仍然写不出来一个像样的窗口程序。许多过来人应该都有类似的困惑吧?其原因是一般 C/C++ 的教材不会教你如何使用操作系统 API 函数的内容。

C/C++ 语言需要直接使用操作系统的接口功能,这就造成了 C/C++ 语言繁、难的地方。如操作内存不当容易引起程序宕机,不同操作系统的 API 接口使用习惯和风格也不一样。接口函数种类繁多,开发者如果想开发跨平台的程序,必须要学习多个平台的接口函数和对应的系统原理。

在应用层开发,直接使用操作系统接口的函数,往往执行效率高、控制力度大。而开发能力仅仅限制于操作系统本身,Java 这类语言,很多功能即使操作系统提供了,如果 Java 虚拟机不提供,开发人员也无法使用。正如著名的编程大师 Charles Petzold 所说:

“显而易见,究竟用哪种方式编写应用程序最好,其实并无一定之规。应用程序本身的特性应该是决定采用何种编程工具的最主要因素,但是无论将来你采用什么样的编程工具,通过了解操作系统 API 从而深入理解操作系统的工作原理,这本身就有很重要的意义。操作系统是一个非常复杂的系统,在 API 之上加一层编程语言并不能消除其复杂性,最多不过是把复杂性隐藏起来而已。说不定什么时候,复杂的那一面迟早会蹦出来拖你的后腿,懂得系统 API 能让你到时候可以更快地挣脱困境。

在基本操作系统 API 之上的任何软件层或多或少都会限制你使用操作系统的全部功能。比如,你或许发现采用 Visual Basic 来编写你的应用程序非常理想,但是就有那么一两项非常基本的功能 Visual Basic 无法支持。往往这个时候你得非要调用基本 API 。作为直接使用操作系统 API 的程序员,我们的活动空间完全由 API 来规范,再没有什么其他方式比直接调用 API 更有效、更灵活多样了。”

总结起来,C/C++ 语言的开发核心建立在直接调用操作系统 API 的基础上,优点是执行效率高、发挥空间大;缺点是,需要经过系统深入的学习,学习周期长,编写代码较复杂,容易出错。

Linux C++ 与 Windows C++ 领域之争

我之所以把这个标题单独列出来,是想纠正现在很多 C/C++ 新人和初学者一些不当的认识,一般有以下几种观点:

  1. Linux C++ 开发就是后台开发,而 Windows C++ 开发就是客户端开发;
  2. 后端开发比客户端开发(前端)高级,因此后端开发行业薪资水平比客户端开发薪资要高;
  3. 我只学 Linux,不学 Windows。

我相信对于 80 和 90 的这一代开发者来说,当初接触计算机并进入软件行业,都是从接触 Windows 开始的。时至今日,大数据、人工智能等各种新技术方兴未艾,移动互联网如火如荼。无论是 Linux 还是 Windows,尤其是 Windows,仍然是我们大多数人工作、学习、娱乐使用最多的操作系统——我们每天都会使用其上的各种软件。使用这些软件像喝水、呼吸空气一样自然,所以很多人就忽视了这类软件的 “基础作用”。

Windows 上的软件开发发展了很多年了,这些领域也比较成熟,一般不再招初中级开发,而是需要水平较高、经验较丰富的高级开发者。这让很多人造成了“Windows C++”开发市场需求已经很小了的错觉。试问,QQ PC 部门这些年对外招了多少人?

Linux C++ 和 Windows C++ 一样,没有孰高孰低之分,只是两种不同的操作系统而已,不要觉得在 Linux 下敲命令就比在 Windows 的图形化界面点击鼠标达高级。

图形化界面之于命令行,是人们对更高级、更方便的工具追求的必然结果。Linux C++ 也不一定就是后台开发,Windows C++ 也不一定就是客户端开发;所谓的服务器与客户端是个相对的概念,即谁给谁提供服务,提供服务的我们认为是服务端(后台),被服务的我们认为是客户端(前台)。而 Windows 作为后台服务的应用也比比皆是,如笔者之前所在的某交易所的服务器后台都是 Windows 下的 C++ 程序;另外如一些游戏类的服务器端,也不少是 Windows 的。

借用《UNIX 编程艺术》这本书的观点,Windows 和 Linux 的哲学理念不一样,Windows 是假设你不会操作,它教你如何操作,而 Linux 是假设你会操作然后进行操作。根据这个理念,Windows 一般是普通人用的多,而 Linux 是程序员用的多。

从编程的角度来说,Windows 的代码风格是所谓的匈牙利命名法,而 Linux 是短小精悍的连字符风格。例如同一个表示屏幕尺寸的整型变量,Windows 上可能被命名为 iScreen 或 cxScreen ,而 Linux 可能是 screen;再例如 Windows 上创建线程的函数叫 CreateThread,Linux 下叫 pthread_create。有时候,我觉得 Windows 的匈牙利命名法反而更容易理解代码。

这里既然提到前端(客户端)开发和后端开发,这里不得不提一下,这二者没有优劣之分。其侧重点和开发思维是不一样的,前端(客户端)开发一般有较多的界面逻辑,它们是直接与用户打交道,因而一款客户端软件的好坏很大程度上取决于其界面的易用性和流畅性,开发者只要把这一端的“一亩三分地”给管理好即可;而后端服务,对于普通用户是透明的,开发者的程序必须尽量体现“服务”这个字眼,即更有效地为更多的客户端服务,这就要求兼顾请求响应的正确性及时性流畅性

由于服务软件也是运行在某台物理机器上的程序,鉴于 CPU、内存、网络带宽资源有限,而服务程序一般是长周期运行的,因此必须合理地分配和使用资源(如尽量回收不再使用的各种资源)。开发者应从全局考虑,不能在某个“客户端”这一棵树上“吊死”。

从个人的职业发展来看,建议从事客户端开发的人员适当地了解一下服务器开发的思路,反过来也建议从事后端开发的人员去学习一下客户端开发,二者相得益彰。从个人的技术提高来说,也是很有帮助的。

例如您要学习一套开源的软件代码,如果您熟悉客户端和服务器的基本开发和调试技巧,您可以更好地学习它。而在工作上,一个项目,往往是由客户端和服务器程序组成,如果您都熟悉,您可以站在一个更高的角度去审视它、规划它,这也是架构师的基本要求之一。

最后就是很多读者关心的客户端和服务器的薪资问题,这个没有绝对的谁高谁低,因人而异,因能力而异,因岗位而异。

如何看待 C++ 11/14/17 新标准

C++ 开发者有个不成文的规定:即使您对 C++ 很熟悉,也不要在简历上写上您精通 C++,原因很简单—— C++ 这门语言包含的东西实在太多了,没有人能真正“精通”所有。

C++ 既支持面向对象设计(OOP),也支持以模板语法为代表的泛型编程(GP)。而且新的 C++ 标准和遵循 C++ 新标准的编译器也层出不穷,这些年,C++ 变化越来越大、越来越快,从最初业界和开发者翘首以盼的 C++11 标准,历经 C++14、C++17 到今天的 C++20,这门语言与之前的版本差别越来越大,更多原来需要使用第三库的功能也被陆续添加到 C++ 标准库中。以致于 C++ 之父 Bjarne Stroustrup 也开始对这门语言表示担忧:

“C++11 开始的基础建设尚未完成,而 C++17 在使基础更加稳固、规范性和完整性方面,基本没有做出改善。相反地,却增加了重要接口的复杂度,让人们需要学习的特性数量越来越多。C++ 可能在这种不成熟提议的重压之下崩溃,我们不应该花费大量的时间为专家级"

"
即可阅读全文

打开微信"扫一扫",将本文章分享到朋友圈

快给朋友分享吧!

收藏 收藏

1236人已收藏