c++ 预处理之正整型实现方法
副标题[/!--empirenews.page--]
虽然通过一系列的奇技淫巧,让预处理也图灵完备一把,但是用预处理来做计算,真的很吃力不讨好。因为预处理一开始设计出来的目的,就没什么野心,原本就仅仅只是为了做简简单单的文本替换工作,并没有想过要成为正儿八经的编程语言,即便是最最缩水版脚本语言的功能要求都达不到。只是后来,实在是大量要求要批量自动生成代码,特别是c++11之前的版本玩什么模板元编程,铺天盖地的要有大量相似的代码。这些代码用其他工具来生成,当然形式会更加漂亮,但是始终还是用原生的预处理来做这种事情会更加的方便,否则每次修改,都要运行一遍外部工具,都麻烦啊!本人是倾向于用预处理来生成代码的。另外,c++11之后,的确原来很多需要宏来生成代码的场合已经不必要了,但是因为c++11的类型推导能力大大加强了之后,发现又有一大波地方可以用宏来生成代码了。并不是说C++中的宏是必不可少之物,但是用了宏,真的可以减少很多很多的重复代码,起码纸面上的代码清爽了很多。 预处理的原生数据类型就只有符号,然后符号只支持##的并接运算,同时,预处理也能识别并接后的结果(否则,并接运算就没意义了),如果是宏函数,就进行调用操作,如果是宏符号,就替换文本,如果什么都不是,就什么都不做,保留符号。但是这样的弱鸡类型,显然远远不能满足离经叛道的码猿需要。经过大量的宏编程的尝试之后,可以很肯定一点,预处理里面只能再模拟出来一种数据类型,那就是正整数,虽然通过补码运算来仿真负数,但是由于预处理里面的符号不能包含减号(-)字符,当然要花大力气捣鼓负整数也是可以的,只是使用上也不方便也不直观,性价比不高,基本上,必须用宏来生成代码的地方,都可以不需要负整数的。 另外,预处理也没有变量类型的概念,不要说强类型,就连弱类型也不是,完全就是无类型。正整数类型的概念全靠码猿人肉编译器来维护,一个循环的宏代码生成一般都是来来回回也不知道调用了多少层宏调用,任何一个地方出错,有时候是几吨密密麻麻的中间失败代码(编译器的预处理缓冲溢出,弃械投降),有时候就完全没有输出,没有任何一丁点的提示,简直是大海捞针的找问题。因此,在用宏循环生成代码时,必须小心翼翼,步步为营,不得不感慨,正儿八经语言里面的类型真是好东西啊。 其实,数据类型并不重要,重要的是数据上能够支持的运算集合以及这些运算能运用的场合。 #define _ZPP_INC_JOIN(_A,_B) _ZPP_INC_JOIN_IMP1(_A,_B) #define PP_INC(x,) _ZPP_INC_JOIN(_ZPP_INC_,x) 同样的方式,再如法泡制PP_DEC,从256开始,一直递减到0为止。对于大于256的数,就不支持了,那就都是未定义操作。这样子,通过PP_INC(n),就得到n+1;而PP_DEC(n),则是n-1。比如PP_INC(PP_DEC(9)),其结果肯定是9了。很好,这样子,在预处理中就实现了自然数自增1和自减1的运算了。另外,对于大于256的数,比如512传递给PP_INC,就只得到一个_ZPP_INC_512的符号,完全没有任何意义。 然后,两个自然数是否相等的判断,也非常重要,必须支持。但是,在此之前,要实现一个宏函数PP_NOT,用来判断入参是否为0。为0的话,则函数返回1,否则,就返回0。也即是: 这样子之后,显然PP_NOT(n)就可以变成PP_ARG1(_ZPP_NOT_n,0)的形式了。PP_NOT不是只需一个入参吗?为何后面还要带省略号,纯粹是为了后面各种变态的运用,取悦编译器。已经用宏来写代码了,就不必再遵守什么清规戒律,只要能完成任务就行了。 至于PP_ARG1的实现,就很简单了,如下所示, 然后通过两次取反的函数,再补上函数PP_BOOL,如果入参>0,就返回1,否则返回0,类似于整型到bool的强制类型转换。 有了这些的铺垫之后,要比较两个自然数是否相等,就简单了。其实没什么神秘的,就是针对从0到255,重复256个以下形式的#define语句, (编辑:广西网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |