全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

c++ 预处理之正整型实现方法

虽然通过一系列的奇技淫巧,让预处理也图灵完备一把,但是用预处理来做计算,真的很吃力不讨好。因为预处理一开始设计出来的目的,就没什么野心,原本就仅仅只是为了做简简单单的文本替换工作,并没有想过要成为正儿八经的编程语言,即便是最最缩水版脚本语言的功能要求都达不到。只是后来,实在是大量要求要批量自动生成代码,特别是c++11之前的版本玩什么模板元编程,铺天盖地的要有大量相似的代码。这些代码用其他工具来生成,当然形式会更加漂亮,但是始终还是用原生的预处理来做这种事情会更加的方便,否则每次修改,都要运行一遍外部工具,都麻烦啊!本人是倾向于用预处理来生成代码的。另外,c++11之后,的确原来很多需要宏来生成代码的场合已经不必要了,但是因为c++11的类型推导能力大大加强了之后,发现又有一大波地方可以用宏来生成代码了。并不是说C++中的宏是必不可少之物,但是用了宏,真的可以减少很多很多的重复代码,起码纸面上的代码清爽了很多。

预处理的原生数据类型就只有符号,然后符号只支持##的并接运算,同时,预处理也能识别并接后的结果(否则,并接运算就没意义了),如果是宏函数,就进行调用操作,如果是宏符号,就替换文本,如果什么都不是,就什么都不做,保留符号。但是这样的弱鸡类型,显然远远不能满足离经叛道的码猿需要。经过大量的宏编程的尝试之后,可以很肯定一点,预处理里面只能再模拟出来一种数据类型,那就是正整数,虽然通过补码运算来*负数,但是由于预处理里面的符号不能包含减号(-)字符,当然要花大力气捣鼓负整数也是可以的,只是使用上也不方便也不直观,性价比不高,基本上,必须用宏来生成代码的地方,都可以不需要负整数的。

另外,预处理也没有变量类型的概念,不要说强类型,就连弱类型也不是,完全就是无类型。正整数类型的概念全靠码猿人肉编译器来维护,一个循环的宏代码生成一般都是来来回回也不知道调用了多少层宏调用,任何一个地方出错,有时候是几吨密密麻麻的中间失败代码(编译器的预处理缓冲溢出,弃械投降),有时候就完全没有输出,没有任何一丁点的提示,简直是大海捞针的找问题。因此,在用宏循环生成代码时,必须小心翼翼,步步为营,不得不感慨,正儿八经语言里面的类型真是好东西啊。

其实,数据类型并不重要,重要的是数据上能够支持的运算集合以及这些运算能运用的场合。
好了,回到上文,我们用_ZPP_INC_N搞了10个数,通过复制粘贴,可以把N增加到255。实际运用中,完全足够用了。

#define _ZPP_INC_JOIN(_A, _B) _ZPP_INC_JOIN_IMP1(_A, _B)
#define _ZPP_INC_JOIN_IMP1(_A, _B) _ZPP_INC_JOIN_IMP2(~, _A##_B)
#define _ZPP_INC_JOIN_IMP2(p, res) res

#define PP_INC(x, ) _ZPP_INC_JOIN(_ZPP_INC_, x)
#define _ZPP_INC_0 1
#define _ZPP_INC_1 2
#define _ZPP_INC_2 3
#define _ZPP_INC_3 4
#define _ZPP_INC_4 5
#define _ZPP_INC_5 6
#define _ZPP_INC_6 7
#define _ZPP_INC_7 8
#define _ZPP_INC_8 9
#define _ZPP_INC_9 10
...
#define _ZPP_INC_255 256

同样的方式,再如法泡制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(0) == 1
PP_NOT(23) == 0,或者 PP_NOT(var) == 0。
记住,预处理提供给我们的原生类型就只有符号和##并接运算,除此之外,别无他物。好像工具太简陋,能完成目的吗?不得不佩服有些码猿的脑洞。以下代码是这样运作的,假设PP_NOT生成以下的调用形式,先不管PP_ARG1,至于符号~,是这样子的,可以看成普通的变量名字,它就是占位符,因为预处理只识别逗号(,),和小括号,至于其他符号,完全无视,那些是C/C++编译阶段才关心的符号。
PP_NOT(0) = PP_ARG1(~, 1, 0)
PP_NOT(n) = PP_ARG1(_ZPP_NOT_n, 0)
然后,让PP_ARG1取第二个参数(码猿的计数是从0开始的,也即是,0即是1,1即是2),就完成任务了。至于_ZPP_NOT_n是什么鬼,那个只是中间生成的临时符号,可以舍弃。我们只需对_ZPP_NOT_0做特别处理。因此,代码可以这样写了。PP_PROBE()用以生成两个入参
#define PP_PROBE() ~, 1
#define _ZPP_NOT_0 PP_PROBE()
#define PP_NOT(_X, ...) PP_IS(PP_JOIN(_ZPP_NOT_, _X))
# define PP_IS(...) PP_ARG1(__VA_ARGS__, 0)

这样子之后,显然PP_NOT(n)就可以变成PP_ARG1(_ZPP_NOT_n, 0)的形式了。PP_NOT不是只需一个入参吗?为何后面还要带省略号,纯粹是为了后面各种变态的运用,取悦编译器。已经用宏来写代码了,就不必再遵守什么清规戒律,只要能完成任务就行了。

至于PP_ARG1的实现,就很简单了,如下所示,
#define PP_ARG0(_0, ...) _0
#define PP_ARG1(_0, _1, ...) _1
#define PP_ARG2(_0, _1, _2, ...) _2

然后通过两次取反的函数,再补上函数PP_BOOL,如果入参>0,就返回1,否则返回0,类似于整型到bool的强制类型转换。
#define PP_BOOL(_X, ...) PP_NOT(PP_NOT(_X))

有了这些的铺垫之后,要比较两个自然数是否相等,就简单了。其实没什么神秘的,就是针对从0到255,重复256个以下形式的#define语句,
#define _ZPP_0_EQUALS_0 PP_PROBE()
#define _ZPP_1_EQUALS_1 PP_PROBE()
#define _ZPP_2_EQUALS_2 PP_PROBE()
...
#define PP_EQUALS(x, y) PP_IS(PP_CONCAT4(_ZPP_, x, _EQUALS_, y))
PP_EQUALS就是将入参并接成_ZPP_x_EQUALS_y的形式,只要x和y相同,也即是说,它们在上面的表格中,那么,道理就如同PP_NOT的实现那样,最后结果就是1了。其实,预处理中没有判断这种玩意,只有表格,只有并接,只有查表。所谓的图灵完备,说白了,没有玄虚的,就是建表,然后查表。对相等比较取反PP_NOT,自然就得到不相等的判断函数。
#define PP_UN_EQUALS(x, y) PP_NOT(PP_IS(PP_CONCAT4(_ZPP_, x, _EQUALS_, y)))
再次建表,就可以得到bool运算的函数,或与
#define PP_OR(a,b) PP_CONCAT3(_ZPP_OR_, a, b)
#define _ZPP_OR_00 0
#define _ZPP_OR_01 1
#define _ZPP_OR_10 1
#define _ZPP_OR_11 1

#define PP_AND(a,b) PP_CONCAT3(_ZPP_AND_, a, b)
#define _ZPP_AND_00 0
#define _ZPP_AND_01 0
#define _ZPP_AND_10 0
#define _ZPP_AND_11 1

再准备一张表格,将字节映射到8个二进制位。
#define _ZPP_BINARY_0 (0, 0, 0, 0, 0, 0, 0, 0)
#define _ZPP_BINARY_1 (0, 0, 0, 0, 0, 0, 0, 1)
#define _ZPP_BINARY_2 (0, 0, 0, 0, 0, 0, 1, 0)
#define _ZPP_BINARY_3 (0, 0, 0, 0, 0, 0, 1, 1)
#define _ZPP_BINARY_4 (0, 0, 0, 0, 0, 1, 0, 0)
...
然后通过模拟计算机组成原理里面的加减乘除的原理,就可以实现四则运算了。对了,整个预处理库的代码都在压缩包上,功能比boost的预处理库强多了,但是代码却少了很多,也容易理解多了,所有代码在vs下面正常运行,其他平台还没有测试。代码包:preprocessor.rar


# c++  # 预处理  # 正整型  # 浅谈c++ 预处理器  # c++ 预处理的图灵完备之引言  # C++编程中变量的声明和定义以及预处理命令解析  # 简介C/C++预处理器的一些工作  # 常用C/C++预处理指令详解  # C/C++预处理浅析使用形式  # 即是  # 这样子  # 都是  # 也不  # 就可以  # 没有任何  # 就没  # 用了  # 是说  # 来做  # 完成任务  # 什么都不  # 大波  # 的是  # 奇技淫巧  # 别无他物  # 清规戒律  # 还没有  # 很好  # 加减乘除 


相关文章: 建站之星在线客服如何快速接入解答?  广州商城建站系统开发成本与周期如何控制?  免费制作海报的网站,哪位做平面的朋友告诉我用什么软件做海报比较好?ps还是cd还是ai这几个软件我都会些我是做网页的?  洛阳网站制作公司有哪些,洛阳的招聘网站都有哪些?  PHP 500报错的快速解决方法  专业制作网站的公司哪家好,建立一个公司网站的费用.有哪些部分,分别要多少钱?  上海制作企业网站有哪些,上海有哪些网站可以让企业免费发布招聘信息?  如何快速生成凡客建站的专业级图册?  平台云上自主建站:模板化设计与智能工具打造高效网站  焦点电影公司作品,电影焦点结局是什么?  教育培训网站制作流程,请问edu教育网站的域名怎么申请?  长沙企业网站制作哪家好,长沙水业集团官方网站?  如何选择高效便捷的WAP商城建站系统?  如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?  ,柠檬视频怎样兑换vip?  名字制作网站免费,所有小说网站的名字?  如何在Windows服务器上快速搭建网站?  为什么Go需要go mod文件_Go go mod文件作用说明  一键网站制作软件,义乌购一件代发流程?  jQuery 常见小例汇总  c# Task.Yield 的作用是什么 它和Task.Delay(1)有区别吗  如何构建满足综合性能需求的优质建站方案?  建站之星在线版空间:自助建站+智能模板一键生成方案  建站之星客服服务时间及联系方式如何?  免费视频制作网站,更新又快又好的免费电影网站?  如何通过老薛主机一键快速建站?  三星网站视频制作教程下载,三星w23网页如何全屏?  如何通过宝塔面板实现本地网站访问?  建站之星北京办公室:智能建站系统与小程序生成方案解析  公司网站制作费用多少,为公司建立一个网站需要哪些费用?  PHP正则匹配日期和时间(时间戳转换)的实例代码  郑州企业网站制作公司,郑州招聘网站有哪些?  昆明网站制作哪家好,昆明公租房申请网上登录入口?  太原网站制作公司有哪些,网约车营运证查询官网?  如何用景安虚拟主机手机版绑定域名建站?  建站之星导航菜单设置与功能模块配置全攻略  网站制作公司广州有几家,广州尚艺美发学校网站是多少?  如何在七牛云存储上搭建网站并设置自定义域名?  云南网站制作公司有哪些,云南最好的招聘网站是哪个?  建站主机系统SEO优化与智能配置核心关键词操作指南  MySQL查询结果复制到新表的方法(更新、插入)  如何选择PHP开源工具快速搭建网站?  建站之星与建站宝盒如何选择最佳方案?  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  桂林网站制作公司有哪些,桂林马拉松怎么报名?  如何确保西部建站助手FTP传输的安全性?  制作网站的模板软件,网站怎么建设?  武汉网站制作费用多少,在武汉武昌,建面100平方左右的房子,想装暖气片,费用大概是多少啊?  大连 网站制作,大连天途有线官网?  如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。