QCon 全球软件开发大会(北京站)门票 9 折倒计时 4 天,点击立减 ¥880 了解详情
写点什么

代码之丑(十)——条件编译那些事儿​

2010 年 12 月 30 日

C 语言出现之初,跨平台是个极大的卖点。于是,我们有机会看到这样的代码:

复制代码
int sys_old_mmap(struct tcb *tcp) {
long u_arg[6];
#if defined(IA64)
int i, v;
for (i = 0; i < 6; i++)
if (umove(tcp, tcp->u_arg[0] + (i * sizeof(int)), &v) == -1)
return 0;
else
u_arg[i] = v;
#elif defined(SH) || defined(SH64)
int i;
for (i=0; i<6; i++)
u_arg[i] = tcp->u_arg[i];
#else
if (umoven(tcp, tcp->u_arg[0], sizeof(u_arg), (char *) u_arg) == -1)
return 0;
#endif // defined(IA64)
return print_mmap(tcp, u_arg);
}

你已经知道了我要说什么了,是的,条件编译。

条件编译在解决跨平台的问题上,确实是个利器,但这么用条件编译,就把它变成了一柄双刃剑。Robert Martin 在《Clean Code》里告诉我们,函数应该只做一件事。从逻辑上来说,这段代码是做了一件事。但是,它还有另外一个维度,也就是条件编译的条件。这个维度的存在让一件事变成了多件事。

无他,提取函数吧!

复制代码
int sys_old_mmap(struct tcb *tcp) {
#if defined(IA64)
return sys_old_mmap_for_ia64(tcp);
#elif defined(SH) || defined(SH64)
return sys_old_mmap_for_sh_or_sh64(tcp);
#else
return default_sys_old_mmap(tcp);
#endif // defined(IA64)
}
int sys_old_mmap_for_ia64(struct tcb *tcp) {
long u_arg[6];
int i, v;
for (i = 0; i < 6; i++)
if (umove(tcp, tcp->u_arg[0] + (i * sizeof(int)), &v) == -1)
return 0;
else
u_arg[i] = v;
return print_mmap(tcp, u_arg);
}
int sys_old_mmap_for_sh_or_sh64(struct tcb *tcp) {
long u_arg[6];
int i;
for (i=0; i<6; i++)
u_arg[i] = tcp->u_arg[i];
return print_mmap(tcp, u_arg);
}
int default_sys_old_mmap(struct tcb *tcp) {
long u_arg[6];
if (umoven(tcp, tcp->u_arg[0], sizeof(u_arg), (char *) u_arg) == -1)
return 0;
return print_mmap(tcp, u_arg);
}

好,经过一番分解,函数比原来的规模小了许多,更重要的是,我们把针对不同的条件做法已经拆解开来了。

相对于原来的版本,这是一段可以接受的代码。制约原有代码的出现,我们也可以用一个简单的规则:

  • 条件编译里面不允许包含多条执行语句。

不过,这还不是终点。针对上面的情况,这种改法没有问题,因为提取出来的小函数在各个平台上都可以编译,但如果涉及到特定平台的操作,简单的提取就不起作用了。比如,用到了 Windows API 的代码在 Linux 上恐怕连编译这关都过不了。

一种可能的解决方案是,把不同条件的内容放进不同的文件。

复制代码
int sys_old_mmap(struct tcb *tcp) {
long u_arg[6];
int i, v;
for (i = 0; i < 6; i++)
if (umove(tcp, tcp->u_arg[0] + (i * sizeof(int)), &v) == -1)
return 0;
else
u_arg[i] = v;
return print_mmap(tcp, u_arg);
}
(ia64.c)
int sys_old_mmap(struct tcb *tcp) {
long u_arg[6];
int i;
for (i=0; i<6; i++)
u_arg[i] = tcp->u_arg[i];
return print_mmap(tcp, u_arg);
}
(sh.c)
int sys_old_mmap(struct tcb *tcp) {
long u_arg[6];
if (umoven(tcp, tcp->u_arg[0], sizeof(u_arg), (char *) u_arg) == -1)
return 0;
return print_mmap(tcp, u_arg);
}
(default.c)

同之前的一个差别在于,不再有一个统一的 sys_old_mmap,而是大家有了各自的 sys_old_mmap,分别放在了对应的文件里。构建的时候,我们可以根据不同的条件编译链接不同的文件,这样就可以回避前面提到的问题。

之前谈及的那些丑陋代码大多是在一个文件内部做着各种各样的变换,而这次的变动显然大了很多,甚至需要配合构建过程的修改。为了对付丑陋的代码,我们总是有办法的。

即便劳神费力的修改构建过程,我依然认为是值得的。其实,我们想要的,无非是明天的日子好过一些。

作者简介:

郑晔,ThoughtWorks 公司咨询师,拥有多年企业级软件开发经验,热衷于探索各种程序设计语言在真实软件开发中所能发挥的威力,致力于探寻合理的软件开发方式,加入 ThoughtWorks 公司后,投入到敏捷开发方法的实践之中,为其他公司提供敏捷开发方法方面的咨询服务。他的 blog 是梦想风暴

查看原文:代码之丑(十)

2010 年 12 月 30 日 17:173488
用户头像

发布了 22 篇内容, 共 12.1 次阅读, 收获喜欢 38 次。

关注

评论

发布
暂无评论
发现更多内容

《实战Java高并发程序设计》.pdf

田维常

电子书

《自己动手写网络爬虫》.pdf

田维常

电子书

《循序渐进Linux (第2版)》.pdf

田维常

电子书

《从零开始学微信小程序开发》.pdf

田维常

电子书

大数据处理黑科技:揭秘PB级数仓GaussDB(DWS) 并行计算技术

华为云开发者社区

数据库 并行算子 计算

《HTML5与CSS3基础教程(第8版)》.pdf

田维常

电子书

《零成本实现Web性能测试——基于Apache JMeter》.pdf

田维常

电子书

《Python源码剖析》.pdf

田维常

电子书

渣渣2本学历CRUD一年半,决定改变现状,努力学习两个月成功拿到美团30k offer

Java成神之路

Java 程序员 架构 面试 编程语言

Alibaba技术大牛丢给我一份Spring Cloud笔记,在GitHub的热度居然高达81.6k标星,太强了!

Java成神之路

Java 程序员 架构 面试 编程语言

配置企业管理系统,什么样的工作流才有用

雯雯写代码

工作流 企业管理系统

《腾云:云计算和大数据时代网络技术揭秘》.pdf

田维常

电子书

《Go语言实战》.pdf

田维常

电子书

《人人都是架构师:分布式系统架构落地与瓶颈突破》.pdf

田维常

电子书

Nginx-技术专题-入门教程

李浩宇/Alex

阿里P8Java大神给迷茫的程序员一些中肯建议:“请不要再虚度光阴了!”

Java成神之路

Java 程序员 架构 面试 编程语言

面试大厂被算法难倒惨遭滑铁卢?这份字节内部大佬整理的《数据结构与算法》学习笔记你一定要看看!

Java架构之路

Java 程序员 架构 面试 编程语言

央行数字货币为人民币国际化之路提供推动力

CECBC区块链专委会

数字货币

直播预告 | 应用加固防破解,4.1折就够了

蚂蚁集团移动开发平台 mPaaS

安全攻防 App风险 mPaaS

《MySQL开发者SQL权威指南》.pdf

田维常

电子书

架构师训练营第一期 - week7

习习

《Java Web企业项目实战》.pdf

田维常

电子书

聆听无声的话语:手把手教你用ModelArts实现手语识别

华为云开发者社区

AI 图像识别 手语

阿里技术四面+交叉面+HR面成功拿到offer,谁说双非本科进不了大厂?

Java成神之路

Java 程序员 架构 面试 编程语言

英特尔顶级技术专家合力缔造精品:Linux开源网络全栈详解

周老师

Java 编程 程序员 架构 面试

阿里云视频云技术专家 LVS 演讲全文:《“云端一体”的智能媒体生产制作演进之路》

阿里云视频云

媒体 音视频

《Docker全攻略》.pdf

田维常

电子书

《用户网络行为画像》.pdf

田维常

电子书

《一线架构师实践指南》.pdf

田维常

电子书

深入理解Java虚拟机第三版,通俗易懂,大牛带你轻松搞懂JVM性能调优

Java架构之路

Java 程序员 架构 面试 编程语言

区块链+能源 大放异彩

CECBC区块链专委会

区块链 能源

边缘计算隔离技术的挑战与实践

边缘计算隔离技术的挑战与实践

代码之丑(十)——条件编译那些事儿​-InfoQ