﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-学习心得（code）-随笔分类-C</title><link>http://www.cppblog.com/superlong/category/21188.html</link><description>superlong@CoreCoder</description><language>zh-cn</language><lastBuildDate>Fri, 11 Mar 2016 08:38:10 GMT</lastBuildDate><pubDate>Fri, 11 Mar 2016 08:38:10 GMT</pubDate><ttl>60</ttl><item><title>Clang 宏定义初探（二）</title><link>http://www.cppblog.com/superlong/archive/2016/03/11/212977.html</link><dc:creator>superlong</dc:creator><author>superlong</author><pubDate>Thu, 10 Mar 2016 17:20:00 GMT</pubDate><guid>http://www.cppblog.com/superlong/archive/2016/03/11/212977.html</guid><wfw:comment>http://www.cppblog.com/superlong/comments/212977.html</wfw:comment><comments>http://www.cppblog.com/superlong/archive/2016/03/11/212977.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/superlong/comments/commentRss/212977.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/superlong/services/trackbacks/212977.html</trackback:ping><description><![CDATA[<div><h1>Clang 宏定义初探（二）</h1>本篇总结下这几天看的宏的一些看到的用法。<br /><h2>1、参数粘结</h2>这是一个类似 shell 之类的脚本语言的特性，可以利用这个特性完成一些重复度比较高的编码的简化。<br />例如，对proc文件系统进行绑定的时候，需要在/proc/test/目录下，简历3个文件接口，test1、test2、test3.<br />可以这样写<br /><dt><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">#define</span>&nbsp;BIND(x)&nbsp;test##x-&gt;read_proc=test##x##_read</div></dt>在使用的时候，就可以<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all">BIND(1);&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">展开为test1-&gt;read_proc=test1_read;<br /></span>BIND(2);&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">展开为test2-&gt;read_proc=test2_read;</span></div><br />不管是从语义还是编码复杂度，都降低了。<br /><br /><h2>2、参数字符化</h2>在使用单个 # 号，作为函数式宏的参数前缀时，可以让宏的内容变成字符串，比如说：<br /><dt><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">#define</span>&nbsp;print(x)&nbsp;do{\<br />printf(#x);\<br />printf("=%d\n",x);\<br />}<span style="color: #0000FF; ">while</span>(0)</div></dt>使用的时候，直接写：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">int</span>&nbsp;t&nbsp;=&nbsp;1;<br />print(t);</div>结果会是 <strong>t=1</strong>，这个在做日志的时候还是非常好用的。<br /><br /><h3>3、do{...}while(0) 和 ({...})</h3>可以认为是前者是 void 函数，后者是有 return 值的函数。<br />入2中所示，do{...}while(0) 是为了产生一个程序块，当宏里有多条需要语句需要执行时，如果不适用这种do{...}while(0)的形式，可能导致一些隐形的错误,例如：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">#define</span>&nbsp;print(x)&nbsp;{printf(#x);printf("=%d\n",x);</div>正常的：<br />print(t); 是没有问题的，但是如果放在程序段里：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">if</span>(&nbsp;flag&nbsp;)<br />&nbsp;&nbsp;print(t);<br /><span style="color: #0000FF; ">else</span><br />&nbsp;&nbsp;print(a);</div>展开之后，会发现为<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">if</span>(&nbsp;flag&nbsp;)<br />{printf("t");printf("=%d\n",t);};<br /><span style="color: #0000FF; ">else</span><br /><img src="http://www.cppblog.com/Images/dot.gif" alt="" /></div>这个语法就错了。因此，当代码段比较多，且不需要返回值时就用 do{...}while(0)吧。<br />另外一种方式属于 GNU 的扩展，后续在看。<br /><br /><h2>4、多重展开</h2>还是基于打印的例子，我需要打印一些列举的参数值：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">#define</span>&nbsp;P(x)&nbsp;arg##x<br /><span style="color: #0000FF; ">#define</span>&nbsp;print(x)&nbsp;do{printf(#P(x));printf("=%d\n",P(x));}while(0)</div>这个编译通不过，换成以下方式即可：<div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">#define</span>&nbsp;P(x)&nbsp;arg##x<br /><span style="color: #0000FF; ">#define</span>&nbsp;__print(x)&nbsp;do{printf(#x);printf("=%d\n",x);}while(0)<br /><span style="color: #0000FF; ">#define</span>&nbsp;_print(x)&nbsp;__print(x)<br /><span style="color: #0000FF; ">#define</span>&nbsp;print(x)&nbsp;_print(P(x))</div></div><div>修改成这样，解决了想要的解决的问题：<br /><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><span style="color: #0000FF; ">int</span>&nbsp;arg1&nbsp;=&nbsp;1;<br />print(1);</div></div><div>输出结果为：<strong>arg1=1</strong><br />主要涉及的问题在于宏的多次展开，宏每次展开只会对当前的输入参数进行一次展开，当你的输入值也是个宏的时候，就需要使用过度宏，让你的输入接着展开。<br />对于多次展开没有从最根本的原理解释，只是从实验感官上对这个特性做了分析，实际上，自己也不会写出那么复杂的宏（怕中间调用出漏洞）。<br /><br />宏的基本常见用法，都差不多枚举了一番，往后在见到更高级的玩法和比较精髓的写法往后再慢慢补充上来吧，另外GNU的扩展也会在后篇继续学习了解。</div></div></div><img src ="http://www.cppblog.com/superlong/aggbug/212977.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/superlong/" target="_blank">superlong</a> 2016-03-11 01:20 <a href="http://www.cppblog.com/superlong/archive/2016/03/11/212977.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>clang 宏定义初探（一）</title><link>http://www.cppblog.com/superlong/archive/2016/03/08/212947.html</link><dc:creator>superlong</dc:creator><author>superlong</author><pubDate>Tue, 08 Mar 2016 00:44:00 GMT</pubDate><guid>http://www.cppblog.com/superlong/archive/2016/03/08/212947.html</guid><wfw:comment>http://www.cppblog.com/superlong/comments/212947.html</wfw:comment><comments>http://www.cppblog.com/superlong/archive/2016/03/08/212947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/superlong/comments/commentRss/212947.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/superlong/services/trackbacks/212947.html</trackback:ping><description><![CDATA[<h1> Clang 宏定义初探（一）</h1>
<span style="font-size: 24pt;">宏</span>的定义方法是<span style="color: #0000ff; font-size: 13px; background-color: #eeeeee;">#define</span><br />
那么在什么场景下需要用到宏呢？遇到一些重复的东西，简单的有&nbsp;<span style="font-size: 13px; color: #0000ff;">for</span><span style="font-size: 13px; background-color: #eeeeee;">(i&nbsp;</span><span style="font-size: 13px; background-color: #eeeeee;">=</span><span style="font-size: 13px; background-color: #eeeeee;">&nbsp;</span><span style="font-size: 13px; background-color: #eeeeee;">0</span><span style="font-size: 13px; background-color: #eeeeee;">;&nbsp;i&nbsp;</span><span style="font-size: 13px; background-color: #eeeeee;">&lt;</span><span style="font-size: 13px; background-color: #eeeeee;">&nbsp;n;&nbsp;i&nbsp;</span><span style="font-size: 13px; background-color: #eeeeee;">++</span><span style="font-size: 13px; background-color: #eeeeee;">)</span>&nbsp;之类的，为了减少繁琐的编码，可能使用<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">#define</span>&nbsp;FO(i,N)&nbsp;for(i=0;i&lt;N;i++)</div>
为了增强可读性，比如说设置一个数组常亮大小，可以使用<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">#define</span>&nbsp;N&nbsp;1001</div>
宏看起来感觉很好用，但是潜藏了很多问题，在实际使用中需要小心谨慎（当然带来大部分问题的，还是编码者自己或者合作方）。<br />
<span style="font-size: 10pt;">例</span>如，现在要求两个数的最小值，最初会写出如下宏：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">#define</span>&nbsp;MIN(A,B)&nbsp;A&lt;B?A:B</div>
正常情况下也是可以使用无误的：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->1&nbsp;#include&nbsp;&lt;stdio.h&gt;<br />
2&nbsp;<span style="color: #0000FF; ">#define</span>&nbsp;MIN(A,B)&nbsp;A&lt;B?A:B<br />
3&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;main()<br />
4&nbsp;{<br />
5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;a&nbsp;=5,&nbsp;b&nbsp;=6;<br />
6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%d",&nbsp;MIN(a,&nbsp;b));<br />
7&nbsp;}</div>
然而，当你发布你的代码或者很久以后自己再去调用时，可能写成：<br />
<div>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->MIN(a&lt;4?a:5,&nbsp;b)</div>
看起来也没啥问题，实际执行一下发现，结果是5，偏离预期！事实上，宏即使单纯的代码展开，当你展开上面的式子之后会发现，实际执行的代码是<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->a&lt;4?a:5&lt;b?a&lt;4?a:5:b</div>
对于一直用括号来解决优先级问题的我来说，这种展开完全无法理解，于是参看了内核代码，发现更安全的写法为：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">#define</span>&nbsp;MIN(A,B)&nbsp;(A)&lt;(B)?(A):(B)</div>
这种写法规避了令人厌恶的优先级问题！本以为这样就完成了一个安全的宏定义，但是事实上还有其他问题！<br />
<div>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">float</span>&nbsp;a&nbsp;=&nbsp;1.0f;<br />
<span style="color: #0000FF; ">float</span>&nbsp;b&nbsp;=&nbsp;MIN(a++,&nbsp;1.5f);<br />
printf("a=%f,&nbsp;b=%f",a,b);</div>
</div>
<div>神秘的a++，同样按照刚才的思路展开，因为宏里面会有两次A的展开，所以a++将被执行两次，再次偏离预期。对于这种情况，我们需要用到一个GNU C的赋值扩展，即使用({...})的形式。这种形式的语句可以类似shell，在顺次执行之后，会将最后一次的表达式的赋值作为返回。举个简单的例子，下面的代码执行完毕后a的值为3，而且b和c只存在于大括号限定的代码域中：<br />
<div>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">int</span>&nbsp;a&nbsp;=&nbsp;({<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;b&nbsp;=&nbsp;1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;c&nbsp;=&nbsp;2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;+&nbsp;c;<br />
});</div>
</div>
<div>结果是// =&gt; a is 3<br />
基于这种特性，我们可以在宏里面为每个传入的参数进行一个拷贝，然后再对拷贝后的参数进行实际的比较运算，那么最终实现了一个比较安全的最小值比较的宏定义：<br />
<div>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">#define</span>&nbsp;&nbsp;min(x,y)&nbsp;&nbsp;({&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">typeof</span>(x)&nbsp;&nbsp;__min1&nbsp;=&nbsp;(x);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">typeof</span>(y)&nbsp;__min2&nbsp;=&nbsp;(y);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;(<span style="color: #0000FF; ">void</span>)&nbsp;&nbsp;(&amp;&nbsp;__min1&nbsp;==&nbsp;&amp;&nbsp;__min2);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;__min1&nbsp;&lt;&nbsp;__min2&nbsp;&nbsp;?&nbsp;__min1&nbsp;:min2}) &nbsp;</div>
</div>
<div>最后这一步跳跃有点大了，首先是 typeof 作用是得到参数的类型，其次是(void)&nbsp;(&amp; __min1 == &amp; __min2); &nbsp;这个神秘的写法是为了验证二者的类型是否一致，当然外侧我们确实用了GNU的扩展({...})。<br />
<span style="font-size: 24pt;">写到这里</span>，涉及到了另外两个问题，GNU扩展是啥？另外我们用宏是为了节省代码，同时为了省去一些小函数的多次重复调用的参数入栈降低性能的问题，那么内联函数也有这样的效果，什么是内联函数呢？</div>
</div>
</div>
</div><img src ="http://www.cppblog.com/superlong/aggbug/212947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/superlong/" target="_blank">superlong</a> 2016-03-08 08:44 <a href="http://www.cppblog.com/superlong/archive/2016/03/08/212947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>