<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>鬼の领地 &#187; 宏</title>
	<atom:link href="http://blog.upsuper.org/tag/%e5%ae%8f/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.upsuper.org</link>
	<description>the place where there are some ghost appearing...</description>
	<lastBuildDate>Wed, 19 Oct 2011 13:21:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>跨编译器的 C 语言 NaN 支持 (纠正)</title>
		<link>http://blog.upsuper.org/nan-support-for-cross-compiler-of-c/</link>
		<comments>http://blog.upsuper.org/nan-support-for-cross-compiler-of-c/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 11:19:59 +0000</pubDate>
		<dc:creator>upsuper</dc:creator>
				<category><![CDATA[雕虫小技]]></category>
		<category><![CDATA[C/C++/C#]]></category>
		<category><![CDATA[VC]]></category>
		<category><![CDATA[兼容性]]></category>
		<category><![CDATA[宏]]></category>
		<category><![CDATA[微软]]></category>
		<category><![CDATA[标准化]]></category>
		<category><![CDATA[编译器]]></category>

		<guid isPermaLink="false">http://blog.upsuper.org/?p=933</guid>
		<description><![CDATA[之前的版本犯了一个重大的错误！我错了……没有经过认真的实验就贴出来…… 正文开始前，先看一个式子： 1 x != x 大家觉得，这个东西的返回可能为 true 么？事实上是可能的，只要这个 x 是 NaN，并且这个 C 编译器符合 IEEE 754 的标准。 所谓 NaN，即 Not A Number，不是一个数。这是 IEEE 754 国际浮点数运算标准当中规定的一个特殊值，这个值由于不是一个数，所以有很多奇怪的特性，比如上面这个不等于其本身。 虽然有这么个东西，而且是国际标准，不过我们也知道，这世界上总有那么些公司是不喜欢理会国际标准的，邪恶的 M$ 就是其中之一。而 Visual C++ 6.0 的 C 编译器也就“有幸”成为了少有的不能完全兼容 IEEE 754 的编译器之一。 至此，我们发现一个问题：邪恶的 M$ 的东西中，总是最垃圾的流传的最广，IE6 如此，VC6 也是如此。另外，在此声明一下，这里讲的全部是 C，不是 C++，在 C++ 中另外有一些比较符合标准的方式同时被各个编译器兼容。 OK，回归正题，既然 VC6 的编译器是个渣，可我们有的时候还是不得不让自己的代码与之兼容，于是就有了各种解决办法。 首先明确一下，我们现在需要两样东西，一是一个可以用于赋值的 NaN (在我的程序中作为一个标记值使用)，另一个是一个用于判断一个数是否为 NaN 的函数或宏。基于上面对 NaN [...]]]></description>
			<content:encoded><![CDATA[<p><strong style="color: red;">之前的版本犯了一个重大的错误！我错了……没有经过认真的实验就贴出来……</strong></p>
<p>正文开始前，先看一个式子：</p>

<div class="wp_codebox"><table><tr id="p9338"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p933code8"><pre class="c" style="font-family:monospace;">x <span style="color: #339933;">!=</span> x</pre></td></tr></table></div>

<p>大家觉得，这个东西的返回可能为 true 么？事实上是可能的，只要这个 x 是 NaN，并且这个 C 编译器符合 IEEE 754 的标准。</p>
<p>所谓 NaN，即 Not A Number，不是一个数。这是 IEEE 754 国际浮点数运算标准当中规定的一个特殊值，这个值由于不是一个数，所以有很多奇怪的特性，比如上面这个不等于其本身。</p>
<p>虽然有这么个东西，而且是国际标准，不过我们也知道，这世界上总有那么些公司是不喜欢理会国际标准的，邪恶的 M$ 就是其中之一。而 Visual C++ 6.0 的 C 编译器也就“有幸”成为了少有的不能完全兼容 IEEE 754 的编译器之一。</p>
<p>至此，我们发现一个问题：邪恶的 M$ 的东西中，总是最垃圾的流传的最广，IE6 如此，VC6 也是如此。另外，在此声明一下，这里讲的全部是 C，不是 C++，在 C++ 中另外有一些比较符合标准的方式同时被各个编译器兼容。</p>
<p>OK，回归正题，既然 VC6 的编译器是个渣，可我们有的时候还是不得不让自己的代码与之兼容，于是就有了各种解决办法。<br />
<span id="more-933"></span><br />
首先明确一下，我们现在需要两样东西，一是一个可以用于赋值的 NaN (在我的程序中作为一个标记值使用)，另一个是一个用于判断一个数是否为 NaN 的函数或宏。基于上面对 NaN 的介绍，在一个符合标准的编译器上，我们可以很容易地给出如下宏：</p>

<div class="wp_codebox"><table><tr id="p9339"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p933code9"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define NaN (0.0 / 0.0)</span>
<span style="color: #339933;">#define IsNaN(x) ((x) != (x))</span></pre></td></tr></table></div>

<p>对于上面这样的 NaN 定义，VC6 不同寻常的会发生编译错误：</p>

<div class="wp_codebox"><table><tr id="p93310"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p933code10"><pre class="text" style="font-family:monospace;">error C2124: divide or mod by zero</pre></td></tr></table></div>

<p>可能也有人会问，难道除 0 不应该是错误么？事实上 IEEE 754 里面就是规定 0.0 / 0.0 = NaN。这里我给出一个我个人的理解：学过高等数学的人大约都会知道，一个无穷小除以一个无穷小，他们的极限可能是无穷大或任何实数，而由于浮点数的精度限制，这里的 0 可能不是真的 0，而是一个很小很小极其趋近于 0 的数，类似无穷小，于是有这样的规定吧。再来看看 IsNaN，这个宏就更无敌了，VC6 的编译器会自作聪明的直接把它优化为 false……</p>
<p>那么对于 VC6 我们该怎么办呢？</p>
<p>查阅了许多资料，最后我们在 MSDN 中翻出了一份年代久远的文档：<a href="http://msdn.microsoft.com/en-us/library/aa298428%28VS.60%29.aspx">_isnan</a>。这里的 _isnan 是 VC6 在 float.h 中定义的一个函数，用于校验一个数是否为 NaN。现在的问题就剩下，我们如何生成 NaN，以及如何判断编译器呢？</p>
<p>那么我们来思考一下，除了用零除零，还有什么方法可以生成 NaN 呢？翻看了 <a href="http://www.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF">IEEE754 标准文档</a>，看到了开平方一个负数也应该是 NaN。这一点应该很好理解，开平方一个负数应该得到一个虚数，而虚数不是一个实数，所以也就 Not a Number 了~于是最后形成了下面一段预处理指令：</p>

<div class="wp_codebox"><table><tr id="p93311"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p933code11"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#ifdef _FPCLASS_SNAN</span>
<span style="color: #339933;">#include &lt;math.h&gt;</span>
<span style="color: #339933;">#define NaN sqrt(-1)</span>
<span style="color: #339933;">#define IsNaN(x) _isnan(x)</span>
<span style="color: #339933;">#else</span>
<span style="color: #339933;">#define NaN (0.0 / 0.0)</span>
<span style="color: #339933;">#define IsNaN(x) ((x) != (x))</span>
<span style="color: #339933;">#endif</span></pre></td></tr></table></div>

<p>虽然调用 sqrt 可能有效率问题，而且额外的需要引用 math 头文件，不过还算几乎完美地解决了 NaN 跨编译器的兼容性问题~事实证明，这段代码可以通过 VC6 的编译器正确地编译并执行。</p>
<p>另外说一点东西，就是如何在 Linux 下用 VC6 的编译器呢？这个问题我想我解决的其实是不完美的，不过也留在这里吧。</p>
<p>首先我下载了一个免安装版的 VC6，然后解压。接着找到了 VC6/VC98/Bin 目录，里面有非常著名的 VC6 编译器的主程序 CL.EXE 以及连接器 LINK.EXE。对于编译器这种纯运算的程序，wine 的兼容性还是比较优美的。不过需要一个额外的 dll 文件支持：mspdb60.dll，这个文件<a href="http://www.dll-files.com/dllindex/dll-files.shtml?mspdb60">很容易载到</a>，解压到 wine 的系统目录 (~/.wine/drive_c/windows/system32) 就可以了。</p>
<p>接下去就是如何编译了……我的方法比较老土，是将待编译的文件复制到编译器目录，然后执行类似下面命令：</p>

<div class="wp_codebox"><table><tr id="p93312"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p933code12"><pre class="bash" style="font-family:monospace;">wine CL.EXE 源文件.c <span style="color: #000000; font-weight: bold;">/</span>I..<span style="color: #000000; font-weight: bold;">/</span>Include <span style="color: #000000; font-weight: bold;">/</span>o可执行文件.exe <span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">link</span> <span style="color: #000000; font-weight: bold;">/</span>LIBPATH:..<span style="color: #000000; font-weight: bold;">/</span>Lib</pre></td></tr></table></div>

<p>其中“源文件.c”和“可执行文件.exe”是很容易理解的，“/I../Include”是使编译器能知道 include 的文件应该去哪里找，而“/link”表示后面的部分是连接器参数，“/LIBPATH:../Lib”就是表示静态链接库的地址了~</p>
<p>最后再说说如何将 GCC 可以编译的程序移植到 VC6 中。GCC 实现了 C99 标准，但 VC6 因为出现在 1998 年 (怎么正好早一年……不过就算是 99 年出也未必会支持 C99 就是了……)，所以不支持 C99，于是所有的变量必须在函数最前面声明，不能混入代码内部。此外，在 VC6 当中，void 指针是不能进行运算的。还有就是不能用“//”开头的行注释，必须使用块注释。这是我移植过程中遇到的主要麻烦。</p>
<p>事实上，在 GCC 当中，可以验证大多数 C89 的限制，只要在编译的时候用如下语句：</p>

<div class="wp_codebox"><table><tr id="p93313"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p933code13"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">gcc</span> <span style="color: #660033;">-ansi</span> <span style="color: #660033;">-pedantic</span> <span style="color: #660033;">-o</span> 可执行文件 源文件.c</pre></td></tr></table></div>

<p>只要把其中所有的 warning 全部消灭掉就可以啦~</p>
<p>当然，最好的方法莫过于在 VC6 的编译器中直接测试了……</p>
<p>最后最后，M$ 实在是……唉……这个世界上不明真相的孩子果然是占大多数的……</p>
<hr />
<p>关于修改的部分：之前的版本错误的使用 _FPCLASS_SNAN 这一校验函数 _fpclass 返回值当作 NaN 来使用。既然查到了这个，这里也顺便说一下这个东西吧。在 VC 的 float.h 库里面有 _fpclass 这个函数，用于检验一个浮点数的类型，可能的返回值都在 float.h 里面，如下：</p>

<div class="wp_codebox"><table><tr id="p93314"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code" id="p933code14"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define _FPCLASS_SNAN   0x0001  /* signaling NaN */</span>
<span style="color: #339933;">#define _FPCLASS_QNAN   0x0002  /* quiet NaN */</span>
<span style="color: #339933;">#define _FPCLASS_NINF   0x0004  /* negative infinity */</span>
<span style="color: #339933;">#define _FPCLASS_NN     0x0008  /* negative normal */</span>
<span style="color: #339933;">#define _FPCLASS_ND     0x0010  /* negative denormal */</span>
<span style="color: #339933;">#define _FPCLASS_NZ     0x0020  /* -0 */</span>
<span style="color: #339933;">#define _FPCLASS_PZ     0x0040  /* +0 */</span>
<span style="color: #339933;">#define _FPCLASS_PD     0x0080  /* positive denormal */</span>
<span style="color: #339933;">#define _FPCLASS_PN     0x0100  /* positive normal */</span>
<span style="color: #339933;">#define _FPCLASS_PINF   0x0200  /* positive infinity */</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://blog.upsuper.org/nan-support-for-cross-compiler-of-c/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>两小段 C 的宏</title>
		<link>http://blog.upsuper.org/two-pieces-of-macro-of-c/</link>
		<comments>http://blog.upsuper.org/two-pieces-of-macro-of-c/#comments</comments>
		<pubDate>Sun, 27 Dec 2009 04:21:36 +0000</pubDate>
		<dc:creator>upsuper</dc:creator>
				<category><![CDATA[雕虫小技]]></category>
		<category><![CDATA[C/C++/C#]]></category>
		<category><![CDATA[宏]]></category>

		<guid isPermaLink="false">http://blog.upsuper.org/?p=930</guid>
		<description><![CDATA[很久没写 blog 了……大学生活可比高中忙碌多了，哪个混蛋骗我说大学轻松来着……学的东西又难，作业又多，还有学生会活动……啊，我多想回到一中…… 最近忙着帮同学写大项目，用 C。话说，对于让没学过编程的人学 C 实在是一件很残酷的事情，即使我现在写仍然觉得很可怕……不过写着写着，觉得 C 实在是一个很神奇的语言，指针和宏是如此的优美~ 下面贴两个我在写那项目的时候用到的宏： 1 2 3 4 5 6 7 #define EXPAND_SPACE(type, p, num, max) { \ if ((num) + 1 &#62;= (max)) { \ if ((max) &#60; 16384) (max) &#60;&#60;= 1; \ else (max) += 512; \ (p) = (type*)realloc((void*)(p), (max)); \ } \ } 这个是我用来动态扩充空间用的宏，可以非常方便的动态增加需要的空间，这样就不需要为应该预分配多少空间烦恼了~ 1 [...]]]></description>
			<content:encoded><![CDATA[<p>很久没写 blog 了……大学生活可比高中忙碌多了，哪个混蛋骗我说大学轻松来着……学的东西又难，作业又多，还有学生会活动……啊，我多想回到一中……</p>
<p>最近忙着帮同学写大项目，用 C。话说，对于让没学过编程的人学 C 实在是一件很残酷的事情，即使我现在写仍然觉得很可怕……不过写着写着，觉得 C 实在是一个很神奇的语言，指针和宏是如此的优美~</p>
<p>下面贴两个我在写那项目的时候用到的宏：<br />
<span id="more-930"></span></p>

<div class="wp_codebox"><table><tr id="p93017"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p930code17"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define EXPAND_SPACE(type, p, num, max) { \
  if ((num) + 1 &gt;= (max)) { \
    if ((max) &lt; 16384) (max) &lt;&lt;= 1; \
    else (max) += 512; \
    (p) = (type*)realloc((void*)(p), (max)); \
  } \
}</span></pre></td></tr></table></div>

<p>这个是我用来动态扩充空间用的宏，可以非常方便的动态增加需要的空间，这样就不需要为应该预分配多少空间烦恼了~</p>

<div class="wp_codebox"><table><tr id="p93018"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="code" id="p930code18"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define SORT_RESULT(name, type, get, cmp, c1, c2) \
void SortResult_##name(int l, int r, Row **rows, int start) { \
  int i = l, j = r; \
  type m = get(rows[(i+j)/2], start); \
  Row *tmp; \
  \
  do { \
    while ((cmp)(m, get(rows[i], start)) c1 0) ++i; \
    while ((cmp)(m, get(rows[j], start)) c2 0) --j; \
    if (i &lt;= j) { \
      tmp = rows[i], rows[i] = rows[j], rows[j] = tmp; \
      ++i, --j; \
    } \
  } while (i &lt;= j); \
  \
  if (i &lt; r) SortResult_##name(i, r, rows, start); \
  if (l &lt; j) SortResult_##name(l, j, rows, start); \
}</span>
&nbsp;
<span style="color: #339933;">#define SORT_RESULT_CHAR(name, c1, c2) \
  SORT_RESULT(Char##name, char*, GET_CHARS, strcmp, c1, c2)</span>
&nbsp;
<span style="color: #339933;">#define SORT_RESULT_FLOAT(name, c1, c2) \
  SORT_RESULT(Float##name, float, GET_FLOAT, MyNumCmp, c1, c2)</span>
&nbsp;
SORT_RESULT_CHAR <span style="color: #009900;">&#40;</span> Asc<span style="color: #339933;">,</span> <span style="color: #339933;">&gt;,</span> <span style="color: #339933;">&lt;</span><span style="color: #009900;">&#41;</span>
SORT_RESULT_CHAR <span style="color: #009900;">&#40;</span>Desc<span style="color: #339933;">,</span> <span style="color: #339933;">&lt;,</span> <span style="color: #339933;">&gt;</span><span style="color: #009900;">&#41;</span>
SORT_RESULT_FLOAT<span style="color: #009900;">&#40;</span> Asc<span style="color: #339933;">,</span> <span style="color: #339933;">&gt;,</span> <span style="color: #339933;">&lt;</span><span style="color: #009900;">&#41;</span>
SORT_RESULT_FLOAT<span style="color: #009900;">&#40;</span>Desc<span style="color: #339933;">,</span> <span style="color: #339933;">&lt;,</span> <span style="color: #339933;">&gt;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>这个很明显是快排~出于效率考虑，我不得不写4个排序……可是我觉得这样非常不好，代码重用性太低了，就写了个宏，就像上面那样~很偷懒吧~</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.upsuper.org/two-pieces-of-macro-of-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

