标签 C 下的文章

在TeX文档中插入源代码

近期有了在TeX文档中插入源代码的需要。TeX的\verbatim可以帮助你保留输入text的原始格式,但用于输入源代码还是显得不够专业。Google了一下发现TeX中支持插入源代码的包也有不少,如LGrind、Listings等。LGrind似乎没有包含在TeX Live的默认安装包中,用apt-get尝试安装LGrind,发现居然要占用近200M的空间,遂放弃之,最后我选择了Listings宏包。

Listings宏包短小而强大,其典型应用方式如下:

\usepackage{listings}
\lstset{…}

\begin{lstlisting}
#include
int main(int argc, const char *argv[]) {
    printf("Hello World!\n");
    return 0;
}
\end{lstlisting}

\lstinputlisting{HelloWorld.c}

其中\lstset用于全局设置插入源代码的类型、各种语法元素的样式、边框和行号设置。你的源码只需包裹在\begin{lstlisting}和\end{lstlisting}之间,源码就能按照之前设置的格式显示。\lstinputlisting支持将一个独立的源代码文件load进来,并按\lstset的格式显示。下面是一个插入C语言源码的例子:

\lstset{ language={[ANSI]C},
         showspaces=false,
         showtabs=false,
         tabsize=4,
         frame=single,
         framerule=1pt,
         framexleftmargin=5mm,
         framexrightmargin=5mm,
         framextopmargin=5mm,
         framexbottommargin=5mm,
         %numbers=left,
         %numberstyle=\small,
         basicstyle=\tt,
         directivestyle=\tt,
         identifierstyle=\tt,
         commentstyle=\tt,
         stringstyle=\tt,
         keywordstyle=\color{blue}\tt }

\begin{lstlisting}
#include
int main(int argc, const char *argv[]) {
    printf("Hello World!\n");
    return 0;
}
\end{lstlisting}

上面lstset中每种语法元素的style都设置为\tt。说到\tt,就不能不提到西方字母字族的种类,分为serif、sans serif和monospace三类。其中serif来源于荷兰语, "衬线"的意思,又称为Roman,一般用于正文的主字体,感觉很正式,我们常用的"Times New Roman"字体就归于此族; sans serif中的sans来源自法文,意为“非”,这类字体比较平滑,字体较大,适于在标题中使用,如"Arial"字体。monospace是等宽字族,也称为typewriter,程序源代码用此族字体表示更为美观,常见的字体包括Courier New、Lucida Console等。其中\tt指的就是使用monospace字族; \rm表示使用serif字族,\sf则是使用sans serif字族的意思。

确定了字族后,我们可以通过TeX preamble区的字体设置得知具体的字体,如在上面例子中,我们是这么设置字体的:
\setCJKmainfont{WenQuanYi Micro Hei}
\setCJKsansfont{WenQuanYi Micro Hei}
\setCJKmonofont{WenQuanYi Micro Hei}

\setmainfont{Times New Roman}
\setsansfont{Arial}
\setmonofont{Courier New}

CJK相关的字体设置影响的是中文字体,而真正对代码起作用的是后面的英文字体设置。这里我们的mono字体设置为了"Courier New",这样我们的源码就会以Courier New的形式展现出来。

我更新了之前制作的book和ppt的TeX模板,以支持插入源代码,有意者可在此下载

给assert加上返回值,不给力!

众所周知,assert是程序调试阶段的一柄利器,可以帮助程序员快速的定位代码问题。但一般来说当程序部署到生产环境的时候,我们会选择关闭assert。不过由于历史原因,我们运行在生产环境下的程序中的assert依旧发挥着作用,这样一把双刃剑就悬在了我们头上。

我们用的是自己的assert实现,这个实现没有C标准库中assert实现那么普适,不过可以满足我们自己需要的功能,它在运行时可以将断言失败信息记录到文件中以便事后分析,并调用了C运行库的assert让进程退出。

在生产环境下开启assert似乎确非惯例,但这也许还谈不上对与错,更多可以看成是当时开发者们的一种选择,在“让程序带着bug继续运行”和“遭遇bug时尽早让程序退出”两者之间,他们选择了后者。当然这也可能是当时他们的一个无奈的选择:在产品诞生初期,Bug较多,为了快速在生产环境定位Bug而开启了assert。

不过时过境迁,客户对产品质量的要求越来越高,我们除了在线下通过各种方法提升产品质量外,在线上当程序出现Bug时的处理方式也要考虑做适当变化,遭遇Bug直接主动退出导致业务瞬间中断的方式被越来越多的开发人员质疑。或者现在的开发人员也是迫于一些外部压力,宁愿选择让程序带着Bug运行下去。

昨天我们针对这个问题做了一个内部讨论,考虑修改自有assert的实现,去除对C库assert的调用,只保留断言失败的信息记录。这样就不会导致程序遇Bug立即退出的情况。不过仍有一个项目组认为这种方案不能解决他们系统中遇到断言失败时无法自恢复并继续健康运行的问题,希望能在代码中感知断言失败,并对错误现场进行一些修复性处理,比如如果断言失败发生在加锁后,希望断言发生后能直接走到解锁环节。最后居然给出了一个让人哭笑不得的方案:给assert加上一个特定的返回值表示程序出现异常(多为Bug)。

先不谈给assert加上返回值有悖assert设计的初衷,如果真的给assert加上了返回值,那意味着什么呢?据不完全统计有如下几点需要改动:
1、assert的实现彻底颠覆,如果按照C标准库中对assert设计的要求,甚至可能是很难实现的;
2、你完全不能忽视assert,因为它还有返回值,甚至当断言失败时,会直接退出使用assert的那个函数;
3、大量遗留库代码和业务层代码需要判断assert的返回值以及使用assert的函数的返回值,增加对assert返回的所谓特殊错误码的处理;
4、实在想不出这个"恐怖"的想法还能带来什么改变。

对这样一个费力不讨好、不给力的想法我除了反对,还是反对。有这些时间还不如仔细琢磨一下如何提高设计能力和产品质量呢。如果非要这么做,建议放过assert吧,请重新实现一个能检查感知Bug的函数接口吧。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats