我努力让遥远的回声给出我这一天可能发生的事件的线索。(“哈姆雷特”,鲍里斯·帕斯捷尔纳克)。
老实说:我不再那么频繁地用纯C编写了,而且我也很久没有关注这种语言的发展了。然而,最近发生了两件意想不到的事情:С夺回了根据TIOBE的最受欢迎编程语言的头衔,多年来第一本真正有趣的关于这种语言的书出版了。因此,我决定花几个晚上学习关于c2x的材料,c2x是C的未来版本。
在这里,我将与大家分享我认为它最有趣的新功能。
我相信你们中的大多数人都知道C是如何开发的,但是,对于任何不知道的人,让我先解释一下术语,然后再简要地复述一下该语言的故事。
1989年,已经非常流行的编程语言C语言达到了认可的新高度,成为美国国家标准(ANSI)和国际标准(ISO)。这个版本的C被称为C89,或ANSI C,以区别于以前存在的许多半兼容的方言。
语言标准的新版本大约每十年发布一次。目前有四个版本存在:最初的C89、C99、C11和C18。目前还不知道下一个版本何时会发布,因此目前正在开发的版本被称为c2x。
对该标准的修改是由一个特殊的组织进行的,即所谓的WG14。它由来自不同国家的感兴趣的业界代表组成。
在专业的英文文献中,这个小组经常被称为“委员会”,所以我在这里也要这样称呼它。
委员会收到相关各方的建议书,每个建议书都有一个名称(例如N2353)。建议通常包括:引入更改的原因、对其他文档的引用以及对标准的具体更改。提案可以有几个版本,每个版本都有一个唯一的名称。
回到我们的话题,我将这篇文章分成三个部分,并根据标准做出相关更改的可能性进行排序。这三部分内容如下:
我认为是“最多汁”的建议:传闻中未公布的建议,正由委员会成员在幕后讨论。
当我说我不知道这些函数不在标准C库中时,我可能会显得无知。还有什么能比复制字符串更明显、更简单呢?但是不,C不是那样的。C不喜欢它的用户。
主要C编译器的开发人员有一个他们最喜欢玩的游戏:想出最常通过声明和定义的属性表示的语言的扩展。当然,语言本身并没有为这些东西提供任何特殊的语法,所以每个人都需要尽其所能发挥创造力。
为了--不知何故--在不想出几十个新关键词的情况下解决这一烂摊子,委员会想出了一种语法来统治所有人。简而言之,用于指定属性的标准语法将被批准作为下一个版本的一部分。以下是提案中的一个示例:
这里,attr1涉及S1并且=s2=;attr2涉及struct S定义;attr3涉及struct S1类型;attr4涉及S1标识符;attr5涉及S2标识符。
委员会已经投票决定将这些属性包括在标准中,但在标准的更新版发布之前,还有很长一段时间要等待。然而,提案作者已经在玩他们的新玩具了。以下是一些建议的属性:
不建议使用的属性允许您将声明标记为过时,这允许编译器发出适当的警告。
Folththrough属性可用于显式标记Switch Case分支中的位置,其中假定控制流应跨越Case边界。
使用nodisard属性,您可以显式指定需要处理函数返回的值。
如果变量或函数不是故意使用的,您可以用MayseUNUSED属性(而不是惯用的(Void)UNUSED_var)来标记它。
不返回调用位置的函数可以用noreturn属性进行标记。
‘K&;R声明’(读作“在方括号后指定类型时”或“我不理解C中的旧代码”)是函数参数声明的一种形式,早在1989年就已经过时了。它终于要被火烧毁了。换句话说,您将不再被允许这样做:
启蒙终于到了用C编写代码的时候了!函数声明最终将实际完成人们期望它们做的事情:
看起来,这似乎是一个没完没了的传奇故事正在接近尾声。委员会已经接受了这样一个事实,即世界上没有独角兽或虚构的体系结构,而C语言的程序员正在处理2的补码带符号整数表示。
在目前的形式下,这一澄清稍微简化了标准,但在未来,它应该可以消除语言中最受欢迎的未定义行为。
虽然可以说,上述变化在我们的现实中已经存在,但以下一组建议仍在制定中。尽管如此,委员会已经给予他们临时批准,假设提交人表现出尽职调查,他们肯定应该被接受。
我每周定期用C语言编写1-2个试用程序。而且,老实说,我早就厌倦了必须指定未使用的参数的名称。
实现委员会肯定评估的建议之一将意味着我们不必在函数定义中不断指定参数名称:
经过漫长的过渡期,委员会最终决定接受语言中的“新”关键字:true、false、alignas、alignof、bool、static_assert等。最终可以删除像<;stdbool.h>;这样的标题。
在可执行文件中包含来自文件的二进制数据的选项是所有游戏开发人员都会发现非常有用的:
我相信委员会已经意识到,社区知道他们的下一次会议在哪里举行,并且这个预处理指令将毫无疑问地被接受。
看起来,有问题的空宏将被关键字nullptr替换,该关键字等同于表达式((void*)0),并且在类型转换的情况下,必须保留指针类型。任何NULL的使用都应附带编译器警告:
/*我总是忘了为什么需要演员阵容。*/int execl(path,arg1,arg2,(char*)null);/*但幸福近在咫尺*/int execl(path,arg1,arg2,nullptr);
如果这个示例对您没有任何意义,那么看一看man3exec下的Linux文档,您会在那里找到您的启示。
标准库函数错误的处理一直是C语言中的一个长期问题。标准的不同版本中的不幸解决方案、委员会的保守立场和反向兼容性问题的组合都阻碍了找到适合每个人的解决方案。
最后,有人准备为编译器开发人员、超级保守的委员会和我们这些凡人提出一个解决方案:
[[oob_return_errno]]int myabs(Int X){if(x==int_min){oob_return_errno(eRange,int_min);}return(x<;0)?-x:x;}。
让我提请您注意OOB_RETURN_ERRNO属性。这意味着将从该模板函数生成以下函数:
返回带有错误标志的结构的函数和(struct{T return_value;int EXCEPTION_CODE})函数的工作结果的函数。
返回函数工作结果的函数,并忽略参数中可能的错误,从而导致未定义的行为。
编译器可以在这些选项之间进行选择,具体取决于程序员如何使用给定函数:
在这种情况下,如果该功能已正确执行,则会显示一个标志,而errno不受影响。函数调用将错误代码保存到变量,例如,看起来类似。
实际的语法似乎还会改变,但委员会至少在朝着这个方向思考,这是一件好事。
“有效C”的作者和其他委员会成员一起回答了黑客新闻界成员的问题。许多事情与我们上面提到的内容重叠。但是有几点对程序员来说很重要。这些建议尚未制定为提案,但委员会成员暗示,这些领域的工作可能正在进行中。
TYPEOF关键字很久以前就在编译器中实现了,它使编写正确的宏变得更容易。这里有一个教科书上的例子:
#定义max(a,b)\({typeof(A)_a=(A);\typeof(B)_b=(B);\_a>;_b?_a:_b;})。
来自红帽的开发商、委员会成员马丁·塞博(Martin Sebor)坚持认为,一项相关的提案已经在研究中,很可能会获得批准。
一些编程语言,包括由Clang和GCC实现的语言,允许您将释放的资源绑定到变量的词法作用域,或者更简单地说,当控制流超出变量的作用域时调用给定的代码。
纯C语言没有这个选项,而且从来没有过,但是编译器实现CLEANUP(<;Cleanup function>;)属性已经有很长时间了:
“Efficient C”一书的作者、委员会成员罗伯特·西科德(Robert Seacord)承认,他正在研究一项与关键字defer from go类似的提案:
Int do_thing(Void){file*file1,*file2;object_t*obj;file1=fopen(";a_file";,";w";);if(file1==null){return-1;}defer(fclose,file1);file2=fopen(";另一个_file";,";w";);if(file2=null。/*...*/返回0;}。
在本例中,在程序超出do_omething函数体的任何情况下,都将使用file1和file2参数调用fclose函数。
C基因的变化就像基因突变:它们并不经常发生,也很少是可行的,但最终,它们会推动进化向前发展。
C最近一次不幸的变化发生在十年前。就语言的发展而言,最近的一次质量飞跃发生在20多年前。而且,据大家所说,委员会成员现在已经决定考虑向前推进新的标准迭代。
因此,总结一下:使用静态分析器,尽可能频繁地运行Valgrind,并且尽量不要用C编写过大的程序!
另外,我认为“第一本真正有趣的书”这件事对我来说有点言过其实了。有人推荐了一本委员会成员写的名为“现代C”的书,绝对值得一读。