为什么说不用纠结于C/C++的语言标准


以下内容来自知乎用户的回答。

作者:陈硕

据我观察,只有 C/C++ 程序员才会纠结“标准”,别的语言的程序员(C#/Java/PHP/Go/Python/Ruby/JavaScript/Objective-C 等等)似乎不会张口闭口“标准怎么怎么说”,也没有那么多令人讨厌的语言律师。我认为一般的 C/C++ 程序员不需要阅读(通读)标准。标准是给写编译器和标准库的人看的,非常晦涩(通俗地说,就是不说人话),一般人阅读标准的回报率太低,不值得,除非你想成为语言律师。

我的建议是,不用太在意标准,因为只用 C/C++ 标准提供的东西,写不出什么有用的程序来,主要是 IO 方面太弱了。标准只提供了文件和 stdin/stdout,而目录、网络、图形、音频都没有。只用 C/C++ 标准连“清屏”都做不到。如果你真的要考虑编译器之间的可移植性,搞定这些方面的平台差异比搞定语言标准的差异难多了。要说可移植性,我想 JavaScript 程序员更有发言权。

等你工作了就会发现,其实 C++ 没多少可移植性需要考虑。我在 Linux 下写了 10 年 C++ 服务器,一直只需要兼容当前生产环境的操作系统提供的那个 gcc 版本。头 5 年在摩根,一路从 gcc 3.2、3.4、4.1 用到 4.4,因为 RHEL 3/4/5/6 自带的就是这几个版本的 gcc。从可维护性的角度,我们在生产环境下只部署最新两个版本的 RHEL。

再说了,没有哪个主流 C++98/03 编译器实现了 export 关键字,那难道为此你就不写 C++ 程序了?gcc 5 之前的 std::string 采用的是 COW 实现,不符合 C++11 标准,难道你在用上 gcc 5 之前,就不能写 C++11 程序了?要知道 Ubuntu 14.04/Debian 8/CentOS 7 都还停留在 gcc 4.x,去年发布的 Ubuntu 16.04 才用上 gcc 5。

其实,有能力修改编译器的大厂也不太在意标准。我推测,既然 Visual C++ 是微软的,如果微软内部项目需要什么 C++ 特性,跟 Visual Studio 团队说一声估计就能做出来。Visual C++ 也不敢轻易去掉那些不符合标准的扩展(例如 non-const reference 绑定到临时对象)。Google 对 gcc 和 clang 也都有一定的发言权,在 Google 内部,我们这些写 C++ backend 的平时也不会特别在意“符合 C++ 标准”,只要程序在生产环境下表现正确就足够了,反正我们的编译器团队不会没理由地破坏程序的行为。

你完全不用担心“标准过时导致大批代码失效的情况”。你要明白,C/C++ 标准委员会并不雇佣 C/C++ 编译器实现者,实际上他们是求着 C/C++ 编译器作者们实现他们定的标准,实现难度太大的功能会被编译器作者废置(以前的 export 就是一例,我看现在的 GC 也很可能重蹈覆辙)。而雇佣 C/C++ 编译器作者的是 Microsoft/RedHat/Apple/Google/Intel/IBM 这样的大公司(C++98 里就有 IBM 加进去的私货:trigraphs,C++17 终于把它清除了),他们是不会让自己已有的代码无故失效的——由此产生的开发成本谁来承担呢?

C/C++ 标准都是追述性质的(C 语言诞生于 70 年代,1989 年标准化;C++ 诞生于 80 年代,1998 年标准化),制定这种标准有一条重要原则:

Existing code is important, existing implementations are not. http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf

我看完全不必杞人忧天。

同理,我也不太看重 POSIX 标准。Linux 的 epoll 不在任何标准里,难道就不能用了?商用 Unix 已经死得差不多了(你对比一下 APUE 第 1/2/3 版举例用的系统就知道了,今年 Solaris 团队也被解散了),就剩 Linux 一家活得好好的。对于我们这些写 C++ server 的人来说,POSIX (可移植操作系统接口)存在的意义已经不大了,反正也没指望移植到别的系统上去。倒是 Windows 10 主动提供了 Linux 接口,把 muduo 往 Windows 移植的活儿由微软帮我做了,我很欣慰。

作者:pansz

与很多人的嘲讽看法不同,我认为纠结标准并没有错,标准确实需要纠结,但这不是需要普通人类去纠结的东西,只要写编译器的人纠结就够了。

你如果不写编译器,纠结标准就是对编译器的不信任。因为,只要打开了相关选项,编译器自然会把不符合标准的用法都给你揪出来。例如gcc似乎有个叫做pedantic的选项,能够更严格的按照标准去检查。

这个答案中的很多人把符合标准想象成天大的可笑事情,这其实根本没有必要,pedantic检查能通过比你想象的容易得多,换句话说,符合语言标准远远没有很多人想象的那么难,绝大多数程序都能做到,或者只需要进行非常有限的修改。如果你选择支持标准,并不需要花太大代价,熟练之后,根本不会因此而纠结。

至于你为了纠结标准而去搞C89,个人觉得大可不必,毕竟C89距离现在已经28年,再有两年就30年了。C99则是接近20年前的东西。那么,你是觉得30年前的标准更容易过时,还是觉得20年前的标准更容易过时?30年前的标准跟20年前的标准谁可能先被淘汰?答案在你心中。

C++也是类似,第一个C++标准是C++98,距离今天也快20年了,能完整符合它的编译器还是很多的,至于有人说没有编译器完全做到?我的建议:不信谣不传谣。


来回答题主后面提出的问题。

标准过时导致大批代码失效的情况,并不会经常发生,因为这是个严肃的问题,绝大多数情况下,标准的制定都会保持兼容,避免代码大规模失效,做不到这一点的语言往往被人用脚投票。。。py3就是个典型例子,因为不兼容py2导致了十年过去都没能取代py2(很多Linux发行版至今缺省都依然还是py2),最后,py3成为了与py2并行的另外一种语言。

C++设计者原本是打算完全取代C的,所以在设计时才尽最大可能保持与C的兼容性,然而它依然不能做到完全取代,最后,也就成为了与C完全不同的语言,以两种不同语言的身份并行发展了这么多年。

所以题主,完全没有必要担心语言标准更新导致的代码失效,首先这种不兼容一般不会发生,其次如果不兼容真发生了,新的语言标准往往会发展成一种新语言,平行存在,无法取代旧语言。

作者:邱昊宇

我只是想让软件稳定下来,不要出现标准过时导致大批代码失效的情况

对于 C/C++ 来说,其实并不用担心,大多数编译器都是允许你选择语言标准的版本的。只要设置好了目标标准,就不用担心编译器升级导致代码失效,因为编译器作者其实比你更担心兼容问题。比如 gcc / clang 都可以用 -std=c++11 来指定使用 C++11 标准,不用考虑默认或者更高的标准。

而真正面对一个项目,通常也都存在一个确定的语言标准(无论是由人为定义还是被工具链环境所限),这是加入项目后首先需要搞清楚的,脑子里一团浆糊显然会出问题。(使用早期的 MSVC 更容易一团浆糊,原因是早期的 MSVC 只提供一种各个标准特性的大杂烩,不过最近的版本也步入了正轨,开始提供 /STD 选项用以指定标准版本了。)

其实不同版本的标准,如果当作是不同的语言看待,其实一切问题都很好理解。


经常引用标准的人常常会被嘲讽为「语言律师」。不过对于标准本身,似乎只有在你想搞清「X 是不是真的」这类问题时候才有抠字眼的必要,毕竟只有标准才是权威的信息来源。而正常情况下,搞清楚你中意的特性是哪个版本引入或者废弃的、了解某个函数不同版本之间行为的区别就足够了。

当然,与标准互相补完的,其实还有各个编译器的具体「实现」。各个编译器极有可能并不是 100% 实现(或者说兼容)某个标准版本,不过这通常都会明确写在编译器的手册(说明文档)中。比如 clang 的说明里就明确说明 C++98 除了 export 都已支持,而其它更高的标准版本里则精确到了具体特性,给出了要使用特性所需的最低 clang 版本。

你完全可以把「标准」当作是「C++ 这门语言」的接口文档,而「标准」覆盖上「实现」则是「你所用的环境中的 C++」的接口文档。读文档是程序员的本分,而很多人懒得看文档、怎么简单怎么写、不考虑小概率事件、掩耳盗铃地写程序,因此而遇到问题不肯承认自己的错误,才造就了各式各样的「坑」。

余下全文(1/3)
分享这篇文章:

请关注我们:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注