代码编织梦想

摘要:C语言在这过去的五十年间,已经逐渐发展成为极其重要的软件开发语言。本文将深度剖析它是如何与C++、Java、C#、Go、Rust和Python进行竞争,并保持一定优势的。

对于计算机编程语言来说,没有什么技术能沿用半个世纪年,除非它比其他的都好用。C语言于上世纪七十年代初年面世,如今在软件世界仍保持着底层基础开发的主流语言的地位。

有时,一个技术能被长久地流传使用,是因为人们还没有找到一个更好的替代品。在过去的几十年,涌现了大量的语言——甚至出现专门为了挑战C语言的统治地位而设计的新语言。

C真的很难被替代。编程语言调查和软件开发实例都印证了可以用远比使用C语言更好的方式来做开发。但C的地位仍岿然不动,因为它的背后是几十年的积淀和进步。几乎没有语言可以在性能、逻辑、或者普遍性上打败它。

C vs. C++

很自然地,人们会拿C与C++做对比,顾名思义,C++是从C发展而来的。两者之间的不同就在于易扩展性,或者易用性。

语法和方式上,C++与C语言比较接近,但C++提供了很多原生C没有的有用特性:命名空间、模板、异常、内存管理。项目如果对于性能比较敏感,例如数据库和机器学习,通常使用C++编写会对提供系统提高性能更有帮助。

除此之外,C++比C更容易扩展。C++20甚至带来更多的新特性,包括模块、协程、同步库以及其他概念,这些都让模板更易使用。对标准C的最新修订几乎没有新增特性,而是更注重保持向后兼容性。

事实上,所有C++的优点也是它的缺点。C++的特性使用得越多就越复杂,结果就越加难以控制。所以,把自己限制于C++子集的开发者,能避免很多严重的问题。也有些机构想避免C++复杂性,坚持使用C。比如Linux内核的开发团队就会避开C++。

对于前期开发者和维护代码人员来说,选择C是一个避免C++过度使用纠纷的方式。不过,C++也有一系列丰富的高级功能,该用还是要用。但如果简洁明了更适合现在或者未来项目的整体发展的话,C会更有优势。

C vs. Java

在JAVA诞生了几十年之后,其仍然是一般企业级软件开发的主要语言。大多数优秀的企业软件开发项目都是用Java编写,包括绝大多数Apache基金会项目。当开发企业级项目时,Java是一个可行性比较高的语言。

Java的语法大量地借鉴了C和C++。不过与C不同的是,Java不会默认编译成机器语言。相反地,Java运行时环境JVM会将Java代码即时编译到目标环境中运行。在良好的条件下,即时编译的Java可以达到甚至超C的性能。

Java奉行的“一次编写,随处运行”的思想,Java程序仅需小的调整,就能运行在不同的环境。相比之下,尽管C已经移植到许多体系结构中,但是任何给定的C程序可能仍然需要定制才能在Windows和Linux上正常运行。

其可移植性和强大性能的结合,以及软件库和框架的庞大生态系统,使Java成为企业级项目语言的一员。

然而,Java落后C的地方在于,Java从来没有竞争的领域,都是接近底层运行,或直接操作硬件。C代码被转换成机器码,由进程直接执行。Java被编译成字节码,由JVM解释器转换为机器代码的中间代码。此外,尽管Java的自动内存管理在大多数情况下是一种好事,但是C更适合于对有限内存资源有优化要求的程序。

在某些情况下,Java的性能可以接近C。JVM的JIT引擎能在运行时根据程序的行为优化程序,可以进行许多种类的优化,对于预先编辑的C语言而言,这个是行不通的。例如,ApacheSpark使用自定义的内存管理代码绕过JVM进行了一定程度的内存内处理优化。

C vs. C# 与 .Net

在推出近20年之后,C和.NET框架仍然是企业软件世界的主要组成部分。有人说,C#和.NET是微软对Java的一种回应(托管代码编译系统和通用的运行时),因此C和Java之间的许多比较也适用于C和C#/.NET。

与Java(以及Python的某些部分)一样,.NET提供了跨多种平台的可移植性和集成软件的广阔生态系统。考虑到.NET世界中的一些面向企业的开发,这些都是很大的优势。当使用C或任何其他.NET语言开发程序时,可以利用针对.NET运行时编写的各种工具和库。

.NET另一个和Java类似的优点是JIT优化。C和.NET程序可以像C那样提前编译,.NET运行时可即时编译,并能使用运行时的信息进行优化。JIT编译允许对正在运行的.NET程序进行各种优化,这在C中是无法进行的。

和C一样,C和.NET提供了各种直接访问内存的机制。堆、堆栈和非托管系统内存都可以通过.NETapi和对象进行访问。开发人员可以使用.NET中的unsafe模式来实现更高的性能。

不过,值得注意的是,托管对象和unsafe对象之间不能随意交换,它们之间的封装传送需要以降低性能作为代价。因此,减少两者之间的传递,可以最大化的提高.NET程序的性能。

当负担不起托管内存相对于非托管内存的代价时,或者当.NET运行时对于目标环境(如内核空间)是一个很糟糕的选择项或者根本不可用时,那么C语言或许就能解决问题了。与C和.NET不同,C默认情况下会开启直接内存访问。

C vs. Go

Go语法和C很像,大括号作为分隔符、以分号结尾语句。精通C的开发人员通常无需太多困难就可以直接转入Go,甚至把Go的新特性如名称空间和包管理考虑在内也是如此。

代码的易读性是Go的指导设计目标之一,开发人员能够轻松地跟上任何Go项目的速度,并在短时间内精通代码库。C代码库很难摸索,因为它们很容易变成一个由宏和特定于项目或团队的嵌套。Go的语法,以及其内置的代码格式和项目管理工具,都是为了避免这些机制问题。

Go还提供额外的功能,像Goroutines和Channels,用于处理并发性的语言级工具以及组件之间的消息传递。在C语言里面只能自己实现或者用三方库,但是Go以开箱即用的方式提供了这些特性,让我们在开发需要类似功能的软件的时候,变得极其方便。

在内存管理方面,Go与C有较大区别。默认情况下,Go对象被自动管理和回收。对于大多数编程工作来说,这非常方便。但这也意味着任何需要对内存进行特殊处理的程序,会比较难办。

Go的确包含了一个unsafe的包,用于规避Go的一些类型处理的安全性问题,例如使用Pointer类型读取和写入任意内存。但unsafe伴有一个警告,即用它编写的程序“可能不可移植,并且不受Go1兼容性准则保护”。

Go非常适合构建命令行程序和网络服务等程序,因为它们很少需要这样的细粒度操作。但是低级的设备驱动、内核空间操作系统组件以及其他需要对内存布局和管理进行严格控制的任务最好是在C中创建。

C vs Rust

在某些方面,Rust是解决C和C++造成的内存管理难题的新方案,也是解决这些语言许多其他缺点的新方案。Rust编译为本机代码,因此在性能上与C相当。不过,默认情况下,内存安全是Rust的主要卖点。

Rust的语法和编译规则能帮助开发者避免常见的内存管理错误。如果一个程序存在跨过Rust语法的内存管理问题,那么它就不会编译。使用该语言的新手,尤其是从像C这样为此类错误提供了大量空间的语言转过来的新手,他们学习Rust的第一阶段是如何安抚编译器。但是Rust支持者认为,这种短期的痛苦将得到一个长期的回报:不会牺牲速度的更安全的代码。

Rust也可以用它的工具改善C。默认情况下,项目和组件管理是Rust提供的工具链的一部分,与Go相同。有一种默认的、推荐的方式来管理包、组织项目文件夹,以及处理许多其他事情,这最多是临时措施,每个项目和团队处理它们的方式都是不同的。

尽管如此,对于C开发人员来说,被吹捧为Rust优势的东西可能看起来不是那样的。Rust的编译时安全特性不能被禁用,所以即使是再小的Rust程序也必须符合Rust的内存安全限制。默认情况下,C可能不太安全,但在必要时,它更灵活,更宽容。

另一个可能的缺点是Rust语言的体积。即使考虑到标准库,C的新特性也相对较少。Rust特性集正在蔓生并持续增长。与C++相比,较大的Rust特性集意味着更强大的能力,但也更复杂。C是一种较小的语言,但更容易建模,因此可能更适合于看上去有点臃肿的项目中。

C vs Python

现在,每当谈论软件开发时,Python似乎总是会被人们提起。毕竟这是“第二个适合所有事情的语言”,毫无疑问,它是最通用的语言之一,有数千个第三方库。

Python强调的是开发速度而不是执行速度,这是它与C的最大区别。用C语言组装一个程序可能需要一个小时,而用Python只需几分钟。另一方面,该程序在C语言中执行可能只需要几秒钟,而在Python中运行则需要一分钟。但是对于现代硬件来说,Python足够快,这是它获得成功的关键。

另一个主要区别在于内存管理。Python程序完全是由Python运行时进行内存管理,因此开发人员不必担心分配和释放内存的困难。但这里有必要讲明,开发者的轻松是以牺牲运行时性能为代价的,编写C程序需要谨慎地注意内存管理。

其实,Python和C之间有一个很深的联系:参考Python运行时是用C写的。这允许Python程序打包C和C++编写的库。Python生态系统中一些重要的第三方库,如机器学习,其核心是C代码。

如果开发速度比执行速度更重要,程序执行部分可以隔离成独立的组件,而不是分散在整个代码中,那么纯Python或Python和C库的混合比单独使用C更好。否则的话,C仍然是霸主。

感谢XJRsoft提供撰文支持,原文来自Serdar Yegulalp

详情参阅:https://www.xjrsoft.com

 

点击关注,第一时间了解华为云新鲜技术~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/devcloud/article/details/110530272

文字检测(白底黑字)-爱代码爱编程

在这里插入代码片`@TOC import cv2 import numpy as np img = cv2.imread(‘截图.jpg’) cv2.imshow(‘原图片’,img) cv2.waitKey() dst=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) cv2.imshow(‘灰度图’,dst) cv2.waitK

廖雪峰Python学习笔记day11-爱代码爱编程

学习笔记day10 # python study day11 # collections 内建集合模块 # namedtuple 创建自定义tuple对象,规定tuple元素个数,使用属性引用元素 # from collections import namedtuple # Point = namedtuple('Point', ['x', 'y'])

Python 环境下下载并安装NLTK说明-爱代码爱编程

我第一次直接用的是pip install nltk 命令告诉我网络超时,后来我用下面的步骤进执行就下载成功了! 1、在cmd窗口中,进入到python的文件夹内的 Scripts内,我的目录地址是:D:\Python\Scripts 命令行输入:easy_install pip 运行结束后,安装PyYAML and NLTK ,命令行输入:pip inst

python接口测试传form-data参数-爱代码爱编程

抓包的参数是这样的时候表示是form表单,普通的json肯定会报错。 这时需要用一个特殊的json来发送给后台 flight_at={'_token':(None,c_token), 'mawb':(None,mawb), 'file':(None,""), 'export_at':(None,'2020-12-04 11:55

Python中Traceback (most recent call last) 以及No module named pip 故障解决方案-爱代码爱编程

PIP更新后遇见Traceback &No modelu named pip 故障 pip更新遇到故障①Traceback ②No module named pip在尝试后文方法前我试了什么解决方案 pip更新遇到故障①Traceback ②No module named pip 安装包时pip首先提醒我更新,更新时候出现了一些故障…

python,抓取豆瓣电影,再也不用担心没有看不了的电影了-爱代码爱编程

1. 豆瓣抓站流程 分析url特征(菜鸟阶段)对需要抓取的数据设计正则表达式处理HTML中一些特征字符,换行符等 注意异常的处理和字符编码的处理 2. 实现的功能 简单的实现了抓取豆瓣电影Top100的电影名称 3. 后期工作展望 抓取更多的有用数据(如:准确抓取导演, 抓取一个电影评论)使用多线程爬虫学习第三方的爬虫框架(Scrapy)

c语言-杨辉三角---@颜麓-爱代码爱编程

#include<stdio.h> int triangle(int x,int y); int main() //{ // int a[10][10]; // int i,j; // for(i=0;i<10;i++)//将外层所有的1写进去 // { // a[i][0]=1; // a[i][i]=1; // } // //

返回数组的前缀和-爱代码爱编程

给一个数组 nums 。 数组「前缀和」的计算公式为: rtSum[i] = sum(nums[0]…nums[i]) 。 请返回 nums 的前缀和 算法思想:一种方法: 1.读入一个数组——通过循环改变数组下标,按照下标从小到大依次输入数据 for (int i = 0; i < sizeof(nums) / sizeof(int); i++

关于位处理、位运算-爱代码爱编程

关于 C语言的位处理、位运算 位运算——强大到可怕 前言 在单片机开发中,使用C语言是大家首选。C语言是一种面向底层的语言,其中最为强大的便是,能够方便快捷的进行位运算,使得程序代码运行起来更加的有效率。 位运算 程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。 学习计算机的同学对

操作系统-进程调度模拟算法详解-爱代码爱编程

操作系统-进程调度模拟算法详解 一、 实验目的 用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。二、 实验工具 Windows10操作系统、VC++6.0三、 实验步骤 本实验采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法。即依次根据优先级和服务时间 1、首先定义进程结构体。并将该结构体定义

C语言的灵魂—指针-爱代码爱编程

C语言的灵魂—指针 指针是什么 在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。总结来说,指针就是指向地址的变量! 指针的作用 c语言指针可以有效

使用函数求奇数和-爱代码爱编程

使用函数求奇数和 (10分) 本题要求实现一个函数,计算N个整数中所有奇数的和,同时实现一个判断奇偶性的函数。 函数接口定义: int even( int n ); int OddSum( int List[], int N ); 其中函数even将根据用户传入的参数n的奇偶性返回相应值:当n为偶数时返回1,否则返回0。函数OddSum负责计算并