前言

2020年9月,C 20 标准投票通过,预计年底正式发布,C 语言又迎来了重大更新。

提起 C 的新标准,其实有利有弊,有利的是新标准使 C 功能更强大了,新的语法和标准库能够使代码开发更灵活高效。但带来的弊端是语法更复杂,对开发人员的要求更高,使用不当,会导致程序复杂难懂,并容易引入各种问题。

不管大家如何褒贬,C 20 新标准已经是既成事实了,对于 C 的使用者来说,最好是拥抱变化,扬长避短,充分发挥 C 的优势,合理并控制使用各种语言特性,使代码保持简单易懂。

在这个系列文章里,我们来分析一下 C 20 的各个新特性,不但分析新特性的作用和使用方式,也分析其设计的出发点以及带来的影响,为大家在评估是否使用如何使用此新特性时,提供一些参考。

注意:C 20 特性需要 gcc 10 或者 Visual Studio 2019 及以上的版本才支持,本系列的例子使用gcc 10 来编译运行。

c语言数组必须用逗号吗为什么(C20新特性1)(1)

废弃数组下标中的逗号表达式

C 20 中的一个改动,是废弃了在数组中直接使用逗号表达式作为下标,例如下面的代码:

#include <iostream> bool change( int & x ) { x = x * 2; return true; } int main( int argc, char * argv[] ) { int arr[10] = { 0 }; int x = 3; arr[ change( x ), x ] = 3; // (1) arr[ ( x = 1, x 1 ) ] = 4; // (2) for( x = 0; x < 10; x ) std::cout << x << " : " << arr[x] << std::endl; return 0; }

其中(1)处的代码,就是直接使用逗号表达式作为数组的下标,这样的代码在 C 17 及以前的标准中是正常的代码,但到了 C 20 中就成了废弃的代码,编译结果如下:

[foo@test code]$ g -std=c 17 a1.cpp [foo@test code]$ g -std=c 20 a1.cpp a1.cpp: In function ‘int main(int, char**)’: a1.cpp:7:18: warning: top-level comma expression in array subscript is deprecated [-Wcomma-subscript] 7 | arr[ change( x ), x ] = 3; // (1) | ^ [foo@test code]$ ./a.out 0 : 0 1 : 0 2 : 0 3 : 0 4 : 0 5 : 0 6 : 3 7 : 0 8 : 4 9 : 0

C 20 的这个修改,主要的目的,是为了以后可以支持通过多个下标访问多维数组,当然这个多维数组不是 C 语言的多维数组,而是类的形式的多维数组,通过重载 operator [ ] 来实现多个下标参数的访问方式。而当前重载 operator [ ] 只支持一个参数。

// 将来可能可以支持类似下面的语法,定义多维数组类,通过多个下标来访问多维数组元素 mdspan<int, array_property::dimension<2, 3, 5>> foo( /*...*/ ); int value = foo[1, 2, 3];

当然这个只是未来的设想,涉及到可能不兼容的改动,可能需要比较长的过渡时间。而废弃在数组中直接使用逗号表达式作为下标只是迈出开始的一步。不过也有可能 C 标准委员会缩短这个过渡时间,更积极的拥抱变化。C 标准的更新速度比以前更快了,从 auto关键字含义的改变来看,可能这种不兼容的修改其实比我们想象中更容易被接受并广泛使用。

对于当前的代码来说,如果确实需要在数组下标中使用逗号表达式,可以使用(2)处代码的写法,加一个括号,可以避免直接使用逗号表达式,提高代码的兼容性。

arr[ change( x ), x ] = 3; // (1) arr[ ( x = 1, x 1 ) ] = 4; // (2)

逗号运算符有时候在写紧凑一些的代码时比较方便,例如上面调用函数修改一个值时,函数并不返回这个值,可以通过逗号运算符来指定使用这个值。但由于逗号本身也可以用来分隔变量定义、函数参数等,这样就有可能出现二义性。所以如果在一些有可能出现二义性的场合,多加一个括号可以避免潜在的问题。

其实有时候紧凑的代码虽然行数少了,但不一定简洁易懂,还不如拆开成多行,例如:

change( x ); arr[ x ] = 3; // (1) x = 1; arr[ x 1 ] = 4; // (2)

这样的代码虽然行数多了,但更有利于代码的阅读和理解,毕竟代码一般都是需要持续维护的,阅读这段代码的时间比写这段代码的时间长的多,是值得我们多花一点心思,使我们的代码更容易阅读,更容易理解。

,