一个优秀程序员一定不是只掌握一门编程语言,每个语言都有它的优点,同时有它的缺点,有它适应的应用场景,无论是从语言本身还是从软件工程学角度来讲。可以这么说,一个优秀的程序员,可以不依赖于任何一门开发语言,并且可以选择多种开发语言实现复杂系统。之前写过一篇好的程序员应该熟悉的几门编程语言,虽然现在语言有所发展,趋势有所变化,但大部分仍然是适用的。今天我们重拾旧题,一名优秀程序员应该熟悉以下几种编程语言:
4.1 汇编语言
程序员是跟计算机打交道的,是要用指令控制计算机,而汇编语言是控制计算机最直接的编程语言,每一行代码都是一个独立的指令,程序员可以发挥最大的聪明才智,写出最高效的代码,这些对于一些与硬件打交道的程序员是必不可少的。无论什么样的操作系统,启动代码(bootloader)都是由全部或部分的汇编语言写成的,甚至操作系统本身也有部分汇编语言代码。然而,对于一个软件项目而言,除了可行性、 性能,还要考虑一个重要的指标,就是成本,汇编语言的开发、维护成本是很高的,所以只能用在刀刃上。
2004年秋,一个朋友找到我,他在做一个电子锁的项目,之前是用汇编语言写的,大约有2万行,一个月之内就要交付项目了,否则面临着的是违约,而原来的开发人员失联了。在我看了代码之后毅然决然地决定用c语言重写,终于一个月之内,用2500的c代码完成了所有的软件功能与硬件联调测试,顺利交付到了李亚鹏家,据说装锁当天还见到了王菲(为什么没叫上我?)c与汇编语言的开发、维护成本可见一斑。
但是,只有了解了汇编,才能知道其它高级编程语言,最后是如何被解释、编译、执行的,才能知道怎样写出高效的代码。
记得2005年在做一个单片机的项目时,由于片上的rom有限,最后编译完的代码超过了rom的容量,然后就通过不断改变c语言的表达语句,争取在完成同样功能下生成的汇编代码量比较少,do-while, while, -for各种循环都试一遍,再选择一个较好的方式。如果用汇编语言更容易控制一些,不需要依赖编译器的编译水平。
现在很少用汇编的,平时用不到没必要花太多精力,但通读一遍,理解一些指令,了解一下哪些指令执行速度快,哪些指令执行速度慢是必要的,这样你才能知道在用高级语言写算法的时候为什么用移位操作代替,比如:
a = b / 8
会写成
a = b >> 3
,
b = a * 8
会写成
b = (a << 3) & 0x07
因为移位操作只需要一条指令即可执行完成,除法会被转成n个减法,而乘法会被转成n次加法来实现,效率不在同一个量级上,如果是图像处理,每一像素都要进行乘除运算的话与使用移位操作来对比,处理一张图片的时间可能直接影响到一个系统的可用性,比如动态的人脸识别。
4.2 c/c
c/c 经常被放在一起,当成一种编程语言来看待,也对也不对。也为两种语言的编程思想就不太想同,c语言属于过程式编程语言,而c 则是支持面向对像编程,而两都又关系密切,所以常放在一起,但差别真的挺大,而且c 的学习难度要远大于c。关系密切就在于都有一个c,而差异在于2个加号 ,为什么是两个加号而不是一个加号,就是因为差异太大,c 是c的一个超集,在支持面向对像编程的同时,完全兼容了c语言的特性。
要学习c语言的原因在于c语言是与操作系统交互最流行最普遍的语言,所有的操作系统提供的api都是基于c语言的,然后才会在此基础上封装成其它编程语言,所以,在一些计算密集型的应用上,c/c 被广泛使用,如果主要语言采用其它语言如java或c#甚至javascript、python,对于核心的性能瓶颈处都可以通过c语言实现算法,几乎所有的其它高级编程语言都会提供与c语言的交互接口,记住,如果你在用其它的编程语言写一些比较消耗cpu的工作,如果实在解决不了性能问题,就可以考虑加一下用c/c 实现核心算法。
c/c 语言的最大优势在于对内存的控制灵活性,但最大的难度也在于对内存的管理上,一把双刃剑,练好了无敌,练不好自伤。
首先推荐的还是《c primer》,此书是c 的经典教程,书中丰富的教学辅助内容、醒目的知识点提示,以及精心组织的编程示范,让这本书在 c 领域的权威地位更加不可动摇。无论是初学者入门,或是中、高级程序员提升,本书均为不容置疑的首选。
其次,推荐《essentail c 》,该书以四个面向来表现c 的本质:procedural(面向过程的)、generic(泛型的)、object-based(基于对象的)、objectoriented(面向对象的)。全书围绕一系列逐渐繁复的程序问题,以及用以解决这些问题的语言特性来组织。循此方式,你将不只学到c 的功能和结构,也可学到它们的设计目的和基本原理。
《c 编程思想》,该书讲解深入浅出地讲解如休用c 去思考、解决问题,系统性、完整性很强。
然后建议有时间还是读一下c 之父[美] bjarne stroustrup的《the design and evolution of c 》,作者详细介绍了c 的发展史,c 语言设计的原委,可以更好了理解c 是如何被设计出来的,为什么要这么设计,怎么一步步演进的。
健壮性是代码质量的一个重要指标,如何能写出稳定的、健壮的c 代码,一定要学习下《exceptional c 》,对异常安全的保障有详尽的讲解,什么时候要抛出异常,如何捕获异常,如何从异常中恢复,一定细读,即使不经常使用c 语言的程序员也应该认真阅读下本书。
效率又是代码质量的另一个重要指标,《effective c 》、《more effective c 》必读。一共给出了编写高效c 代码的90个准则,是高效代码编写的阶梯。
然后,模板,是c 中最难的一部分,如果能灵活使用模板编程,大型项目的可维护性可以显著提高,但难度相对也较大,c 标准库中的stl但是一些常用模板类的封装,它更是如神兵利器。
最后要推荐的就是c 模板编程的必读书《c 模板元编程》,对开源模板库boost中的mpl进行了比较详细的介绍。mpl是c 对函数式编程的一个精巧包装。
到了最后,其实还想推荐一本《深入浅出mfc》,它系统、深入介绍了微软visual studio中的mfc类库,其实是一个介绍图形化界面类实现的非常好的范例,该书对于图形化界面,无论是pc、mac还是web甚至微信小程序,如果要从底层实现一个图形化界面的框架该书可以作为教科书。
4.3 c#/java
c#和java可以放在一起说,因为这两个语言很像,都是在操作系统上面又封装了一层运行时,相当于虚拟机,可以把c#和java当成运行在虚拟机上的程序,这样的好处就是移植性,因为移植的时候只要有虚拟机即可,就是sdk和clr,目前java在所有的主流操作系统中可以运行,而c#也可以在linux、windows、macos甚至android上运行。有了可移植性,跨平台软件的开发成本就会低很多,但也要牺牲一些特性,尤其是gui程序,不同系统的差异还是有的,很难做到原生程序的性能和体验,商业软件嘛,多是要性能和成本综合考虑的,系统间的差异会随着时间越来越小,开发成本也会越来越低,再c#和java的用武之地
有了虚拟机的隔离安全性和稳定性也会更好,c#、java如果不去通过c/c 的接口调用一些操作系统的api很难把系统整死机,而c/c 相对就更容易一些。
java和c#目前都是比较成熟的语言,尤其是java有着无与伦比的生态优势力,对于大型的系统实现,依然是首选。我也在macos上进行测试了一下java、c#、c 的函数拆分的已开通split函数的性能,测试代码如下:
java:
import java.util.calendar;
import java.util.date;
public class splitperformance {
public static void main(string[] args)
{
string s = "字段1,字段2,字段3,字段4,字段5,字段6,字段7,字段8,字段9,字段10";
calendar cal = calendar.getinstance();
date d0 = cal.gettime();
string[] fields = null;
for(int i=0 ;i<100000000; i){
fields = s.split(",");
}
date d1 = calendar.getinstance().gettime();
system.out.format("time elapsed: %d s\n", d1.gettime() - d0.gettime());
}
}
c#:
using system;
namespace split
{
class program
{
static void main(string[] args)
{
datetime t0 = datetime.now;
string s = "字段1,字段2,字段3,字段4,字段5,字段6,字段7,字段8,字段9,字段10";
string[] fields = null;
for (int i = 0; i < 100000000; i)
{
fields = s.split(",");
}
datetime t1 = datetime.now;
timespan ts = t1 - t0;
console.out.writeline("time elapse {0}s", ts.totalseconds);
}
}
}
c/c :
#include
#include
#include
int main(int argc, const char * argv[]) {
// insert code here...
char const* line = "字段1,字段2,字段3,字段4,字段5,字段6,字段7,字段8,字段9,字段10";
time_t t0, t1;
time(&t0);
size_t len = strlen(line) 1;
char* buff = (char*)malloc(len);
for(size_t n=0; n<100000000; n){
strcpy(buff, line);
char* fields[10] = {
buff};
int i=1;
for(char* p = buff; *p != 0; p){
if( *p == ','){
fields[i] = p 1;
i ;
*p = 0;
}
}
// for(int j=0; j
测试结果:
java: 25.427s
c#: 30.623776s
c : 21s
结果充分证明了java和c#的性能优化得还是相当好的,很久没有对比了过了,这个结果是让我吃惊的,c#在windows上的表现可能会更好。
所以,一般的项目使用java、c#都是没问题的,即使是计算机密集型的代码,尤其是c#支持unfafe模式,可以使用c 的语法,为什么是#,就是4个 号,也就是c 就是因为它是c 的一个超超集,只是语法并不完全兼容c 的语法而特性是基本兼容的,所以学习c#的话上面c 的读一下也是大有裨益的。
c#必读书
《clr via c#》对clr和.net framework 4.0进行深入、全面的探讨,并结合实例介绍了如何利用它们进行设计、开发和调试。这本书在语言方面讲解全面、深入,是学习c#首选,可以对c#有一个全面的了解,以后可以作为案头手册,随时翻阅。
之后再读《c#高级编程》可以略过语言本身的介绍,阅读关于更多界面开发和应用技术,如webform、消息队列、com 、ad等windows系统的编程基本一览无余,也是必读。
然后就是进阶阅读,如何写出高效的c#代码,《effective c#》
java必读书
对于语言本身首选《java核心技术》,一套两本,对java的特性讲解条理清晰,深入、全面,读完了可以作为案头手册,随时翻阅。
另一本《java编程思想》也是非常好的,豆瓣的评分更高,值得细读,尤其是其面向对像的思想介绍,初学者一定好好串讲,这本书软件工程思想融入对java特性的讲解中。
与c 、c#一样,也有一本介绍高效编程的《effective java》
java语言诞生之初是想“write once,run anywhere",但是用java写桌面软件真的不多,除非是跨平台需求比较强烈,确实有几个非常好的软件是用java写的,比如magicdraw、intellij、eclipse等,但主要还是做服务或web比较多。web开发核心框架spring还是要好好学一下的。
学习的不是仅spring框架怎么使用,更应该是它的设计思想,如何才是学好了,就是自己思考一下,如果让自己来重新实现spring能不能实现。而对于容器的学习,下面这本就很不错:
4.4 javascript
javascript现在已经不是只用于web前端开发了,现在成了一个全栈语言,除了开发web前端界面,还可以使用node.js开发后端的服务,还可以使用taro开发微信小程序、android、ios、快应用等移动端应用,真可是一门语言可以干所有的事了。本人还是比较喜欢javascript,因为喜欢c系的语法,它足够简洁、优雅,不是太喜欢python的语法,忍受不了python的__init__, __del__这样的函数名,当然也可能习惯了c系的代码,此外,javascript还是比python性能要好,可以干更多的事儿。javascript还有个typescript的变种,语法更加严谨,更加趋向于面向对象编程,更适合开发大型的项目。
《javascript权威南》必读;《javascript高级程序设计》评分不低,但这本书没有读过,正打算买下来再复习一下。
但这两本书稍微有点儿旧,都是基于emac5的,后面的新性书中没讲,再读一下《深入理解es6》就完美了。
对于typescript也一本就够了《深入理解typescript》
4.5 python
python用得不多,因为不太喜欢,可推荐的不多,《python核心编程》应该也够了。最开始的时候看python的代码缩进都是强制性的,这样确实在语法层面融入软件工程学思想非常好,但语言设计之始考虑不够严谨,导致后面3.x与2.x的不兼容,很多开源代码不能直接使用,浪费大量人力物力;又设计出个虚拟环境,用来解决包的版本不兼容、开发语言版本不兼容的问题,其实是把问题搞得更糟,实践中解决问题更复杂。总得来讲还是不错的语言,它的流行性证明了一切,主要得益于前几年所谓大数据、人工智能的暴发式增长,凭着它的简单性迅速占领了程序员的桌面,但它真的不适合做大的项目。
4.6 结语
现在的编程语言很多,根据不同领域、不同岗位的程序员需要的主要语言各有不同,但无论哪种,要想做到优秀,c/c 都是必须要熟悉的,即使不太熟练,java/c#至少要熟练使用一种,javascript/python必须熟练使用其一,甚至两种都要熟练使用。比如前些天在做爬是的验证码识别的时候选择了javascript,在使用opencv是就费了一些周折,好在对c 比较熟悉,搞定比较快,否则使用python可能会更方便一些,开源的东西,用的人多了坑就没那么多了。
当然用得多的还有php、go、swift等数不胜数,按编译过程分主要有:
- 汇编语言:直接通过计算机所支持的指令集编程;性能可控性比较好,开发难度大,成本高,可移植性差,不同架构的cpu的指令集不同,适合控制硬件的应用,一般用于底层寄存器修改,上层再用c封装;
- 编译型语言(c/c ):直接编译成二进制机器码再执行;这类语言有些可移植性并不高,如basic,主要依赖于编译器,而c/c 的可移植性是很高的,因为gcc可以支持几乎所有的操作系统,而商业的unix系统厂家也都提供了自己的商业编译器,性能更好;
- 解释型语言(python、ruby等):无需编译,一边解释一边执行;
- 即时编译型语言:c#、java都是编译型语言,但又与c/c 等不同,它编译后并不是直接是机器码,而是一种中间语言,这种中间语言执行时再由虚拟机编译成机器码执行,不知道怎么命名,借助即时编译的技术(jit,just-in-time),命合为”即时编译型语言“以区分直接编译成二进制的编译型语言。
另外一角度,从编译思想上分可以分为:
- 结构化编程语言(过程式编程):如c语言等;
- 面向对象程序语言:如c 、java等;
- 函数式编程语言:如lisp等;
- 逻辑式编程语言:如prolog等
而函数式编程语言、逻辑式编程语言适用范围较小,所以,没有应用时有所了解即可,有兴趣的也可以研究了一下,笔者没有研究太多。
有了这些编程语言也可以再读一下《编译原理》以系统地了解编程语言的编译过程,从而方便日后解决疑难问题。
语言,只是工具,最基础的工具学好了,有了较强的表达能力,才能与计算机之间进行流畅的交流,计算机才会听话,高效、可靠地为我们服务。然后,正如上面所说,每一类编程语言至少要熟悉一种,这样会掌握更多的表达方式,更多的与计算机交互的模式,才能在系统设计与实现时选择最合适的编程语言。
然而,要学习的还有很多… (待序)