撒旦的语法



  很多人写代码是照猫画虎这些“猫”最终就变成了教条(注1)旦教条被人熟知区别变量数值功能就被按照教条使用然后用些“胶水”代码组合起来实现需要方案通过对语法深入了解我们可以消除很多“胶水”这篇文章举了几个怪异C语法例子以及如何在不导致歧义(注2)情况下利用(滥用?)他们实现更高效代码

记得返回值

个有关“教条编程”例子将讨论格式化输出sprf下面这段代码写法并不鲜见:
sprf(str1, \"Old v=%d\\t\",v);
/* Some code that plays with v */
sprf(str2, \"New v=%d\",v);
strcat(str1, str2);
prf(str1);

大部分sprf例子使用个临时串变量作为它个参数这就是那个根深蒂固教条:“sprf需要个临时串”然而更好教条是符合语法“sprf需要个指向指针”这提醒我们可以用个返回char *替代它作为第个参数从而节省个临时缓冲区空间例如:
sprf(str, \"Old v=%d\\t\",v);
/* Some code that plays with v */
sprf(strchr(str, \'\\0\'), \"New=%d\",v);
prf(str);

当直接使用指针时候你必须谨慎避免NULL指针在这个例子里str(str,\'\\0\')有效得益于第个sprfsprf还隐藏了个好处-它返回已经写入缓冲区数量-这个数量可以节省次对strlen!检查你代码吧祝你好运!

个例子如果得到长度是为了在某些操作时判定它是否有效你也许会这样写:
len = strlen(GetFileName);
(len > 0)
; /* File name is not null */

然而如果你只是打算用它和0比较为什么不这样写:
(GetFileName[0] != \'\\0\')
; /* File name is not null */

这次我们不仅节省了个缓冲区(这很普通我们直接使用返回值(注3)-这也避免了次额外拷贝)而且还在正确检查了返回值同时消除了前面strlen开销别忘了相同结果可以用等价思路方法得到
(*GetFileName != \'\\0\')
; /* File name is not null */

串只是个(可以用char * 指向)结构上面思路方法同样可以用于返回结构体C类或其指针直接提取你需要元素例如:
struct POINT GetCurrentPos(void);

y;

y = GetCurrentPos.y;


或者

prf(GetDevice->pName);

编译器可能会把结构创建为临时对象然后把他们指针作为隐含参数所以你不必顾虑把结构体拷贝进栈或者出栈开销

从另个角度你还记得“无法返回串”课程吗?其实你可以思路方法很多例如创建个名为STRING结构体里面包含你可以在中返回这样个STRING然后像上面那样引用其中
struct STRING { char str[256]; };

struct STRING GetName(void)
{
.
}

prf(GetName.str);

实际开发中这和传递串指针相比用处很少甚至完全无益但是它确减少了员创建临时变量需求

表达式

   只是表达式如果他们返回个类型(不包括void那并不是种真正类型)那么你就可以把它作为个普通表达式用在任何需要地方例如个while循环这使得循环或者类似流程被快速短路成为可能从C懒惰表达式计算中获益(看补充)
while (1 && GetNextLine(&str))
;

把表达式中1改成0导致整个表达式结果变成0GetNextLine不会被循环永远都不会运行我经常使用这种思路方法在测试代码中取消复杂语句块
(1
&& ComplicatedExpression1
&& ComplicatedExpression2
&& ComplicatedExpression3
)
;

通过把1改成全局静态变量我可以在调试时取消这些代码运行或者通过菜单选项改变它从而在次编译中测试多个项目

结束

我希望还有些新想法告诉你我忘了讲代码也可以使用这种方式移除:
/*
. code here .
//*/
然后用在首行添加个单独/来重新插入这段代码



补充

C使用个懒惰表达式计算器这就是说它只计算需要表达式来推导最终结果是TRUE还是FALSE所以行类似
(fn1 && fn2 && fn3)
.
代码会先计算fn1只有在必要时才继续计算fn2也就是说当fn1返回TRUE时候如果它返回FALSE无论其他表达式如何都无法使得最终结果是TRUE大部分人从如下代码段中凭直觉了解了这点:
(ptr && ptr->Name)
prf(ptr->Name);

这和Pascal是区别


译者:
   本文是Steve Goodwin大作译者水平有限无法很严谨翻译文中要表达内容只能就个人理解尽量在含义上贴近原文尽管对这篇文章某些观点并不十分理解和赞同但是对于开发者来说仍然是很有价值参考
原文链接:http://www.gamedev.net/reference/articles/article1239.asp

注1:原文:This example becomes a templatetemplate本意是模板但是这里理解为教条更能表达感情好恶
注2:原文:without qualying for the IOCCC (International Obfuscated C Code Contest)意译不是很准确
注3:原文:seeing as we use the result directly 这里result指应该是返回值

Tags: 

延伸阅读

最新评论

发表评论