zenny_chen 安沃传媒 技术VP  2017年08月17日
当我们谈论C11标准时,我们在谈论什么
我们很多程序员对C++11标准想必已经如雷贯耳了,而C11标准则似乎比较低调,知道的人并不多。当然,这其中有一部分原因是C11对于C99标准而言,改动幅度并不大,在语法层面上主要是增加了泛型选择表达式,原子数据类型,UTF8、UTF16以及UTF32的字符以及字符串字面量。那么当我们谈论C11标准时,我们在谈论什么呢?

有不少网友表示,现在GNU C语言标准已经成为事实上的C语言标准了。因为我们此前在C99标准中已经看到,C99标准中所增加的语法特性大多来自于GNU语法扩展,再加上之前GCC的广泛使用使得很多嵌入式系统的一些C语言编译器也都基于GCC。而如今,随着LLVM Clang的火爆,使得很多芯片厂商把目光都聚焦于Clang这一基于宽松BSD-2许可证的编译工具链。像AMD现在的OpenCL编译器前端就是基于Clang编译器的;还有ARM Studio 6也基于Clang编译器。而Clang编译器目前支持GCC中大部分的GNU语法扩展,而且它自己也有非常好用的语法扩展,比如Blocks语法使得C语言也能方便地使用Lamba表达式;还有函数重载;特征检查等等。可以说,当我们在谈论C11的时候,几乎不会脱离GNU语法扩展单独讨论,并且GNU语法扩展使C语言更强大!

之前有不少网友表示微软对C语言态度比较冷淡,而事实上微软对C++的态度尽管看似更富热情,但对C++11标准支持、C++14标准支持的力度都不如GCC与Clang,而且还自己引入了一些与众不同的语言行为。笔者在微软官方的技术论坛上也看到,有不少开发者表示MSVC对C99标准一直支持不好表示强烈不满,而微软也承受不了如此压力,因此在Visual Studio 2013中引入了不少C99语法特性,而到Visual Studio 2015则支持得更多一些,像匿名数组、匿名结构体和联合体,指定成员的初始化器,不定参数个数的宏定义等都予以支持。而Visual Studio 2017则更近了一步,直接引入了Clang编译器前端,尽管目前继承在Visual Studio 2017种的Clang编译器前端处于实验状态,但大部分功能都已经稳定了,现在对原子操作还支持得不好,对Blocks的运行时也没支持好,不过对于大部分功能需求而言都已经能很好工作了,有些额外的运行时支持还需要MSVC后端的辅助。所以就放眼现在来看,我们再也不能说微软对C语言持冷淡态度了。托伟大的LLVM项目的福,我们能在Clang上使用的大部分功能均可在VS上使用了。当然,笔者希望MSVC能尽快完善对Clang中原子操作的支持。

C11标准中尽管引入的特性并不是很多,但就笔者看来,这些特性都十分有用!尤其是对UTF-8、UTF-16字符串的支持,以及对原子操作的支持。现在我们在网络上传输的字符编码大都为UTF-8编码格式,因为其通用性强,在全世界都可直接使用。如果我们使用一些拉丁编码格式,GBK编码格式等具有地方特性的编码格式时,在他国浏览器中可能就无法很好支持了。因而,如果我们想把自己做的App、网页展示给世界各国人民的话,那么UTF-8当然是最好的选择。
而对于原子操作则更是刚需了。C语言本身就是为高性能而生的,现在随着大数据分析、机器学习的火热,多核并行计算、大规模核心的并行计算已然从幕后站到了台前。对多核多线程共享的资源免不了需要原子操作进行数据一致性的同步。如果原子操作没有成为标准,那么程序的可移植性就会成为问题。比如在MSVC上一般直接使用内建函数(intrinsic functions)对指定共享对象进行原子操作;而在macOS中,则使用Darwin中所引入的OSAtomic系库函数来实现原子操作;而在一些嵌入式操作系统中也基本都有自己的内建函数,甚至自己写内联汇编予以实现……所以对原子操作进行标准化事不宜迟!现在从OpenCL 2.0开始,也以C11中的原子操作函数作为原型作为原子操作的API了。

有一些程序员对C语言的印象还停留在C90时代,感觉C语言的表达比较原始,有些操作比较繁琐,还有对指针的随意操作比较危险,另外就是各种五花八门的goto语句……其实从C99标准开始,C语言很多方面的书写已经有标准的支持了。比如C99标准开始就引入了标准整数类型以及标准布尔类型。笔者也认为像以前的 int *p = NULL; if(p){ } 这种写法比较原始,而且与其他编程语言也是格格不入。现在许多人都在主张将上述if语句写作为:if(p != NULL){ }更好,而且逻辑上也更清晰。而对于真正的布尔类型对象,比如:bool b = true; 可以直接用if语句表达为:if(b){ }。由于无论是C99标准也好,C11标准也好,它们都向下兼容更老旧的C90标准,因此对布尔类型仍然没有作为头等类型进行使用,尽管C99正式引入了_Bool类型,但是if、while等语句中的表达式仍然是整数常量表达式,而关系操作符的返回类型也都是整数类型,而非纯正的布尔类型。因为C语言的历史非常久远,所以C语言标准也不可能像Swift那样,每次版本升级就做大刀阔斧的修改,完全不顾对老版本的兼容性,如果C语言这么做的话肯定要被骂死,呵呵……所以向上兼容是C语言的优点,尽管由于历史原因,现在很多不优雅的写法仍被允许,但C语言标准也在不断进化,有很多表达形式也被逐步废弃,比如K&R样式的函数定义:void foo(a) int a; { /* ... */ } ;还有三字符转义形式(比如用 ??= 表示 #)等等。而在我们使用C语言时,完全可以用自己认为安全的、优雅的方式来。
比如在早些年,有些C程序员建议使用 if(0 == a) 的方式而不是 if(a == 0) 这种写法,目的就在于万一这里面少打了一个等号,可能就会引发不易察觉的bug。当然,现代编译器对于 if(a = b)这种写法默认会给予警告,如果我们真想表达这种逻辑,那么可以结合笔者上面所提到的用法:if((a = b) != 0),即显式加上关系表达式,而不是让C编译器帮你去做默认处理。倘若你嫌圆括号太多,那么也可以使用逗号表达式:if(a = b, a != 0),这些都是更体面的写法。如果养成这种好的编写代码的习惯,代码就既能看得更清晰,而且又能更安全。

目前基于GNU11的C语言确实已经非常现代化了,尤其对于Clang编译器而言,lambda表达式、类型自动推导,函数重载等等,应有尽有!而且借助GNU语法扩展,我们还能为C语言的用户自定义类型以及全局变量创建名字空间,几乎无所不能!可以说,遵循GNU11标准的C语言已经全面进入了新的时代,为何当前在GitHub上仍然有许多优质的基于纯C语言的开源项目?正是因为C语言已经变得如此强大,如此现代化所致!在许多年以前就有不少C程序员尝试使用C语言来实现面向对象(OO)的特性。今天,笔者借助C语言的函数重载、Blocks语法等现代化语法特性以一种全新的方式来设计C语言的OO行为,这里提供笔者的一份粗略实现,以抛砖引玉:
https://github.com/zenny-chen/C-in-OO-Style

各位如果想要更好地掌握现代化的C语言,以及其更优美的使用方法,笔者推荐《C语言编程魔法书》,让您领略不同凡响的C语言编程!
...全文
1748 1 收藏 17
写回复
17 条回复

还没有回复,快来抢沙发~

发动态
发帖子
非技术区
创建于2007-09-28

4416

社区成员

5.8w+

社区内容

C/C++ 非技术区
社区公告
暂无公告