外星代码生成术之逗号运算符
缩减代码不意味着增加可读性,恰恰相反,过分的缩减代码反而会使代码更难懂,难以维护。本文不提倡滥用扭曲化的外星C语法,只是作为一个集趣式的记录,为初学C派系语言的读者简单介绍一下那些莫名其妙的代码是如何造出来的。
C派系语言为我们提供了许许多的奇怪的运算符,最奇怪的运算符之一当数逗号运算符,它本身并没有太多实际意义“运算”,只是计算各个运算项的值,然后将最右边的运算项的值返回。但这一点使得我们有可能将多个表达式合成为一个:
a = 1;
b++;
c *= 4;
合并为:
a = i, b++, c *= i;
呵,好像意义不大,但如果是在循环中使用,就不一样了:
while (i < n)
{
a = i;
b++;
i++;
}
可简写为:
while (a = i++, b++, i < n) ; /* 注意分号不能少 */
在C++中,由于使用cout等流对象进行的输出语句实际上也是一个表达式,所以对于如下常见的打印整个数组的值的代码:
for (i = 0; i < size; ++i)
cout << a[i] << endl;
使用逗号运算符并利用好自加运算的特性,可以简写为:
for (i = 0; i < size; cout << a[i++] << endl) ; /* 注意分号不能少 */
而对于打印一个二维数组这样的操作,由于循环完一行之后要输出换行,所以外层循环(遍历每一行)不得不使用复合语句:
for (i = 0; i < size; ++i)
{
for (j = 0; j < size; ++j)
cout << a[i][j];
cout << endl;
}
但如果把cout移到循环内,就可以显著减少行数:
for (i = 0; i < size; cout << endl; ++i)
for (j = 0; j < size; cout << a[i][j++]) ; /* 注意分号不能少 */
当然,也可以是
for (i = 0; cout << endl, i < size; ++i)
for (j = 0; cout << a[i][j], j < size; ++j) ; /* 注意分号不能少 */
但使用逗号运算符时一定要注意其隐含的不确定性,如表达式:
++i, cout << a[i], x + y;
如果语言中对各个表达式的求值顺序不确定,那么cout的子表达式所输出的a[i]就无法确定是自加以前的i还是自加以后的i. 使用逗号运算符,以及相关的重载运算符的连续表达式时应当格外注意这一点。
注:由于时间仓促,本文程序片断未经调试,如有错误,欢迎批评指正。