<?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>fleurer &#187; C</title>
	<atom:link href="http://www.fleurer-lee.com/tag/c/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.fleurer-lee.com</link>
	<description>rage and love, story of my life.</description>
	<lastBuildDate>Thu, 02 Sep 2010 11:07:00 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>简介多任务的实现</title>
		<link>http://www.fleurer-lee.com/2010/09/01/%e5%ae%9e%e7%8e%b0%e5%a4%9a%e4%bb%bb%e5%8a%a1/</link>
		<comments>http://www.fleurer-lee.com/2010/09/01/%e5%ae%9e%e7%8e%b0%e5%a4%9a%e4%bb%bb%e5%8a%a1/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 12:22:08 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[翻译]]></category>
		<category><![CDATA[ASM]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Kernel]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645961</guid>
		<description><![CDATA[原文：http://hosted.cjmovie.net/TutMultitask.htm
翻译：fleurer
恩，打算给你的操作系统实现多任务？可以说，多任务是现代操作系统里面最重要的元素之一──没多任务你没脸见人。只跑Bash的linux也有多任务一说──比如debain下边你可以使用Alt+F1,F2,F3,F4切换虚拟终端。不过话说回来，只有一颗cpu的电脑为什么能同时执行10件任务？
答案就是——不为什么，只不过看着像而已。它们切换的速度非常之快，以至于人可以觉得它们是同时执行的。当然也有双核和多核，不过那就不是本文讨论的范畴了。即使有双核多核，像一台普通的的Windows NT(包括XP)内核机器，没有用户登录、没有程序执行，也有约100条线程同时执行。
我们先列些名词好了：

线程 &#8211; 进程的一个分子，可以同时执行。比如你玩的一个游戏是个进程，而这个游戏里面的背景音乐、键盘事件、3D绘图则是独立的线程。
进程 - 在电脑上运行的一个完整程序，有自己的地址空间（通常使用分页实现）。
调度算法 &#8211; 选出下一个要执行任务的方法。可以简单如Round Robina，也可以考虑上优先级，使一进程可以优先得到充足的时间片。调度算法与任务切换的实现无关。
基于栈的任务切换 &#8211; 切换任务的方法之一。按照这个方法，在发生切换时我们把一些信息都&#8221;PUSH&#8221;到进程的栈里，于是只需要切换一个栈把用到的东西（eax, ebx, ds, es）都POP出来即可。这个方法比基于硬件的切换（这里不作讨论）更快，已经几乎是切换的首选。
Round Robin &#8211; 调度算法的一种，可以选出下一个执行的任务。它的实现很简单：把所有的进程（或线程）列出来放到一个表里，反复轮询之，公平分配时间片。

接下来动手吧。添加多任务，你的OS准备好了吗？我这里选择了最简单的方法（Round Robin，上面有介绍），需要：一个内存管理器（memory manager, 只要物理内存就够了）；正确设置的IDT；PIT（可编程中断定时器，译者注） IRQ的hook；在保护模式之下。
我们首先得有一个结构体来表示每个进程的信息。简单起见，先这样：

typedef struct&#123;        //Simple structure for a thread
 unsigned int esp0;   //Stack for kernel
 unsigned int esp3;   //Stack for process
&#125; Thread;
&#160;
Thread Threads&#91;2&#93;;    [...]]]></description>
			<content:encoded><![CDATA[<p>原文：<a href="http://hosted.cjmovie.net/TutMultitask.htm">http://hosted.cjmovie.net/TutMultitask.htm</a><br />
翻译：fleurer</p>
<p>恩，打算给你的操作系统实现多任务？可以说，多任务是现代操作系统里面最重要的元素之一──没多任务你没脸见人。只跑Bash的linux也有多任务一说──比如debain下边你可以使用Alt+F1,F2,F3,F4切换虚拟终端。不过话说回来，只有一颗cpu的电脑为什么能同时执行10件任务？</p>
<p>答案就是——不为什么，只不过看着像而已。它们切换的速度非常之快，以至于人可以觉得它们是同时执行的。当然也有双核和多核，不过那就不是本文讨论的范畴了。即使有双核多核，像一台普通的的Windows NT(包括XP)内核机器，没有用户登录、没有程序执行，也有约100条线程同时执行。</p>
<p>我们先列些名词好了：</p>
<ul>
<li><strong>线程</strong> &#8211; 进程的一个分子，可以同时执行。比如你玩的一个游戏是个进程，而这个游戏里面的背景音乐、键盘事件、3D绘图则是独立的线程。</li>
<li><strong>进程 </strong>- 在电脑上运行的一个完整程序，有自己的地址空间（通常使用分页实现）。</li>
<li><strong>调度算法</strong> &#8211; 选出下一个要执行任务的方法。可以简单如Round Robina，也可以考虑上优先级，使一进程可以优先得到充足的时间片。调度算法与任务切换的实现无关。</li>
<li><strong>基于栈的任务切换</strong> &#8211; 切换任务的方法之一。按照这个方法，在发生切换时我们把一些信息都&#8221;PUSH&#8221;到进程的栈里，于是只需要切换一个栈把用到的东西（eax, ebx, ds, es）都POP出来即可。这个方法比基于硬件的切换（这里不作讨论）更快，已经几乎是切换的首选。</li>
<li><strong>Round Robin</strong> &#8211; 调度算法的一种，可以选出下一个执行的任务。它的实现很简单：把所有的进程（或线程）列出来放到一个表里，反复轮询之，公平分配时间片。</li>
</ul>
<p>接下来动手吧。添加多任务，你的OS准备好了吗？我这里选择了最简单的方法（Round Robin，上面有介绍），需要：一个内存管理器（memory manager, 只要物理内存就够了）；正确设置的IDT；PIT（可编程中断定时器，译者注） IRQ的hook；在保护模式之下。</p>
<p>我们首先得有一个结构体来表示每个进程的信息。简单起见，先这样：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">typedef</span> <span style="color: #993333;">struct</span><span style="color: #009900;">&#123;</span>        <span style="color: #666666; font-style: italic;">//Simple structure for a thread</span>
 <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> esp0<span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">//Stack for kernel</span>
 <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> esp3<span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">//Stack for process</span>
<span style="color: #009900;">&#125;</span> Thread<span style="color: #339933;">;</span>
&nbsp;
Thread Threads<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>     <span style="color: #666666; font-style: italic;">//Space for our simple threads. Just 2!</span>
<span style="color: #993333;">int</span> CurrentTask <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;">//The thread currenlty running (-1 == none)</span></pre></div></div>

<p>还得有个地方来存放线程信息。不过最好事先搞清楚——这个教程已是尽可能的简化了，我们没有让进程在Ring 3下执行，因为那样一来就得考虑TSS——我不想掉这个大坑。Beyond_Infinity同学在一篇类似的教程里用考虑了这个，如果感兴趣不妨一读。</p>
<p>在考虑创建新任务的方法之前，我先说下如何切换任务。其实很简单。</p>
<p>在收到来自PIC的IRQ时，你的IRQ Handler很可能会通过一个&#8217;pusha&#8217;或者&#8217;pushad&#8217;来储存一些寄存器。很好，这就清楚了，你可能使用&#8217;popa&#8217;或&#8217;popad&#8217;以相反的顺序重新得到这些寄存器。大约可以像这样：</p>

<div class="wp_syntax"><div class="code"><pre class="asm" style="font-family:monospace;">_irq0<span style="color: #339933;">:</span>
<span style="color: #00007f; font-weight: bold;">cli</span>    <span style="color: #666666; font-style: italic;">;Disable interrupts</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #0000ff;">0</span> <span style="color: #666666; font-style: italic;">;Push IRQ number</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #0000ff;">0</span> <span style="color: #666666; font-style: italic;">;Push dummy error code</span>
 <span style="color: #00007f; font-weight: bold;">jmp</span> IRQ_CommonStub
&nbsp;
<span style="color: #339933;">..</span> <span style="color: #666666; font-style: italic;">;Other IRQS are here, similiar to above</span>
&nbsp;
IRQ_CommonStub<span style="color: #339933;">:</span>
 <span style="color: #00007f; font-weight: bold;">pusha</span>          <span style="color: #666666; font-style: italic;">;Push all standard registers</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">ds</span>        <span style="color: #666666; font-style: italic;">;Push segment d</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">es</span>        <span style="color: #666666; font-style: italic;">;Push segmetn e</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">fs</span>        <span style="color: #666666; font-style: italic;">; ''</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">gs</span>        <span style="color: #666666; font-style: italic;">; ''</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">0x10</span>  <span style="color: #666666; font-style: italic;">;Get kernel data segment</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">ds</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>    <span style="color: #666666; font-style: italic;">;Put it in the data segment registers</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">es</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">fs</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">gs</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">esp</span>       <span style="color: #666666; font-style: italic;">;Push pointer to all the stuff we just pushed</span>
 <span style="color: #00007f; font-weight: bold;">call</span> _IRQ_Handler <span style="color: #666666; font-style: italic;">;Call C code</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">gs</span>         <span style="color: #666666; font-style: italic;">;Put the data segments back</span>
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">fs</span>
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">es</span>
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">ds</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">popa</span>           <span style="color: #666666; font-style: italic;">;Put the standard registers back</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">add</span> <span style="color: #00007f;">esp</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">8</span>     <span style="color: #666666; font-style: italic;">;Take the error code and IRQ number off the stack</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">iret</span>           <span style="color: #666666; font-style: italic;">;Interrupt-Return</span></pre></div></div>

<p>考你个问题：这些pop可以将当前栈中的数据装回CPU，如果在这个C函数调用时将栈换掉又会怎样？哈哈~到点子上了。如果这样做，整个CPU的状态就切换了。把上面的代码稍微改下：</p>

<div class="wp_syntax"><div class="code"><pre class="asm" style="font-family:monospace;">_irq0<span style="color: #339933;">:</span>
 <span style="color: #666666; font-style: italic;">;Notice there is no IRQ number or error code - we don't need them</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">pusha</span>          <span style="color: #666666; font-style: italic;">;Push all standard registers</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">ds</span>        <span style="color: #666666; font-style: italic;">;Push segment d</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">es</span>        <span style="color: #666666; font-style: italic;">;Push segmetn e</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">fs</span>        <span style="color: #666666; font-style: italic;">; ''</span>
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">gs</span>        <span style="color: #666666; font-style: italic;">; ''</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">0x10</span>  <span style="color: #666666; font-style: italic;">;Get kernel data segment</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">ds</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>    <span style="color: #666666; font-style: italic;">;Put it in the data segment registers</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">es</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">fs</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">gs</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">push</span> <span style="color: #00007f;">esp</span>       <span style="color: #666666; font-style: italic;">;Push pointer to all the stuff we just pushed</span>
 <span style="color: #00007f; font-weight: bold;">call</span> _TaskSwitch <span style="color: #666666; font-style: italic;">;Call C code</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">esp</span><span style="color: #339933;">,</span> <span style="color: #00007f;">eax</span>   <span style="color: #666666; font-style: italic;">;Replace the stack with what the C code gave us</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">mov</span> <span style="color: #00007f;">al</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">0x20</span>   <span style="color: #666666; font-style: italic;">;Port number AND command number to Acknowledge IRQ</span>
 <span style="color: #00007f; font-weight: bold;">out</span> <span style="color: #00007f;">al</span><span style="color: #339933;">,</span> <span style="color: #00007f;">al</span>     <span style="color: #666666; font-style: italic;">;Acknowledge IRQ, so we keep getting interrupts</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">gs</span>         <span style="color: #666666; font-style: italic;">;Put the data segments back</span>
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">fs</span>
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">es</span>
 <span style="color: #00007f; font-weight: bold;">pop</span> <span style="color: #00007f;">ds</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">popa</span>           <span style="color: #666666; font-style: italic;">;Put the standard registers back</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">;We didn't push an error code or IRQ number, so we don't have to edit esp now</span>
&nbsp;
 <span style="color: #00007f; font-weight: bold;">iret</span>           <span style="color: #666666; font-style: italic;">;Interrupt-Return</span></pre></div></div>

<p>有一点需要注意 &#8211; 只要你的C代码返回一个unsigned int，编译器就会把它放到eax寄存器里 &#8211; 简单漂亮（GCC才可以！）。好，接下来做什么？一半了，是的！</p>
<p>接下来考虑创建新任务。这就意味着，我们需要申请内存，并令它的堆栈看起来像是push了所有的寄存器的状态（这一来在切换栈之后，才能有东西pop）。恩，x86体系结构下栈是向下增长的。这就意味着你的push相当于设置esp指向的dword（双字），随后esp减去4。我们在C里模拟出来就行了。幸运的是，这很简单——只需要搞个unsigned int的指针，指向栈顶。每次push后都使用 &#8212; 运算符下移就好。好，就这么创建一个任务：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//This will create a task</span>
<span style="color: #666666; font-style: italic;">//It will make a stack that looks like it has all</span>
<span style="color: #666666; font-style: italic;">//of the stuff of an IRQ handler 'pushed' on it</span>
<span style="color: #993333;">void</span> CreateTask<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> id<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>thread<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> <span style="color: #339933;">*</span>stack<span style="color: #339933;">;</span>
  Threads<span style="color: #009900;">&#91;</span>id<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">esp0</span> <span style="color: #339933;">=</span> AllocPage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000dd;">4096</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//This allocates 4kb of memory, then puts the pointer at the end of it</span>
&nbsp;
  stack <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>Threads<span style="color: #009900;">&#91;</span>id<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">esp0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//This makes a pointer to the stack for us</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">//First, this stuff is pushed by the processor</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #208080;">0x0202</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//This is EFLAGS</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #208080;">0x08</span><span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">//This is CS, our code segment</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>UINT<span style="color: #009900;">&#41;</span>thread<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//This is EIP</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">//Next, the stuff pushed by 'pusha'</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//EDI</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//ESI</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//EBP</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Just an offset, no value</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//EBX</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//EDX</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//ECX</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//EAX</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">//Now these are the data segments pushed by the IRQ handler</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #208080;">0x10</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//DS</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #208080;">0x10</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//ES</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #208080;">0x10</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//FS</span>
  <span style="color: #339933;">*--</span>stack <span style="color: #339933;">=</span> <span style="color: #208080;">0x10</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//GS</span>
  Threads<span style="color: #009900;">&#91;</span>id<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">esp0</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>UINT<span style="color: #009900;">&#41;</span>stack<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Update the stack pointer</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>好，已经设好了任务，接着切换它们。不过怎样？恩，还记得Round Robin吧，你已经知道了！我们只有两个任务，所以在PIT IRQ被触发时只需要知道在执行的是哪个人物，把栈切换成另一个的。再保存当前ESP到旧任务的结构体里。如下：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//Switch between our two tasks</span>
<span style="color: #666666; font-style: italic;">//Notice how we get the old esp from the ASM code</span>
<span style="color: #666666; font-style: italic;">//It's not a pointer, but we actually get the ESP value</span>
<span style="color: #666666; font-style: italic;">//That way we can save it in our task structure</span>
<span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> TaskSwitch<span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> OldEsp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>CurrentTask <span style="color: #339933;">!=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">//Were we even running a task?</span>
 Threads<span style="color: #009900;">&#91;</span>CurrenTask<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">esp0</span> <span style="color: #339933;">=</span> OldEsp<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Save the new esp for the thread</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">//Now switch what task we're on</span>
 <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>CurrentTask <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>CurrentTask <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">else</span> CurrentTask <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span><span style="color: #009900;">&#123;</span>
 CurrentTask <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//We just started multi-tasking, start with task 0</span>
<span style="color: #009900;">&#125;</span>
 <span style="color: #b1b100;">return</span> Threads<span style="color: #009900;">&#91;</span>CurrentTask<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">esp0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Return new stack pointer to ASM</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>随后我们需要由PIT来触发切换任务的asm stub，我假定你已经按照常规将IRQ映射到32-47。如果没，就设置一个IRQ0对应的handler。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">extern</span> <span style="color: #993333;">void</span> irq0<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Our ASM stub</span>
<span style="color: #666666; font-style: italic;">//This is a very simple function</span>
<span style="color: #666666; font-style: italic;">//All it does is put us in the IDT</span>
<span style="color: #993333;">void</span> StartMultitasking<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
IdtSetGate<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>UINT<span style="color: #009900;">&#41;</span>irq0<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Install us in IDT. We multitask NOW!</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>万事俱备，只剩调用这些函数！方便看执行效果起见，在kernel的主文件（可能是main.c）里面添上这两个函数。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//These are just two simple functions that act as</span>
<span style="color: #666666; font-style: italic;">//'threads' to test our multi-tasker on</span>
<span style="color: #666666; font-style: italic;">//I won't try to explain how they work</span>
<span style="color: #666666; font-style: italic;">//Only that they change colors on two letters of the screen</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Also - they must NEVER return - just make an infinite loop</span>
&nbsp;
<span style="color: #993333;">void</span> ThreadTest1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span> VidMemChar <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #208080;">0xB8001</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">;;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>VidMemChar<span style="color: #339933;">++;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> ThreadTest2<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span> VidMemChar <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #208080;">0xB8003</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">;;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>VidMemChar<span style="color: #339933;">++;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>如你所见，执行结果是很容易想象的。不错。加上执行多任务的代码！把几句放到你的主函数（其它函数也行，能执行就好）里面。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">CreateTask<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> ThreadTest1<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Install the first task</span>
CreateTask<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> ThreadTest2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Install the second task</span>
StartMultitasking<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//Start your multitasking OS!</span>
<span style="color: #666666; font-style: italic;">//We're now multitasking. Celebrate!</span></pre></div></div>

<p>该差不多了，你已经可以把你的OS带出单任务的DOS时代了&#8230;多任务多线程的新时代系统！</p>
<p>你可以接着搞搞&#8230;这只是入门而已。简单的Round-Robin算法在很多情况下的效果并不好，不妨看下其他的调度算法，比如Mega Tokyo&#8217;s OS FAQ中列出来的那些。</p>
<p>还有件事情你可能感兴趣，那就是如何将分页整合进来。大多数操作系统都给每个应用程序一个0开始的虚拟地址空间，并一个用户栈。这一来，你就需要给每个任务添加一个页表目录，随后添加一些push和pop以适应CR3中值的改变。</p>
<p>有问题？有建议？Email me at service@cjmovie.net!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/09/01/%e5%ae%9e%e7%8e%b0%e5%a4%9a%e4%bb%bb%e5%8a%a1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>数据结构课设，表达式计算</title>
		<link>http://www.fleurer-lee.com/2010/06/30/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e8%af%be%e8%ae%be%ef%bc%8c%e8%a1%a8%e8%be%be%e5%bc%8f%e8%ae%a1%e7%ae%97/</link>
		<comments>http://www.fleurer-lee.com/2010/06/30/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e8%af%be%e8%ae%be%ef%bc%8c%e8%a1%a8%e8%be%be%e5%bc%8f%e8%ae%a1%e7%ae%97/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 11:28:34 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[备忘]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645901</guid>
		<description><![CDATA[随便写了下，没仔细调试。
大约这么定义
double parse_expr(char *input, char **output);
input就是表达式的字符串，output是解析剩下的部分。如果output==input，就是解析失败。如果正确，返回运算结果。
用起来大约这样

    char *out, *exp=&#34;2+(1+3)*4&#34;;
    double r = parse_expr&#40;exp, &#38;out&#41;;
    if &#40;out==exp&#41;&#123;
        printf&#40;&#34;parse fail\n&#34;&#41;;
        return 0;
    &#125;
    printf&#40;&#34;%s =&#62; %f \n&#34;, exp, r&#41;;

回头想下，思路跟以前写的parser几乎是葫芦画瓢，也该算是递归下降吧。
代码如下
exp.h

double [...]]]></description>
			<content:encoded><![CDATA[<p>随便写了下，没仔细调试。</p>
<p>大约这么定义<br />
double parse_expr(char *input, char **output);</p>
<p>input就是表达式的字符串，output是解析剩下的部分。如果output==input，就是解析失败。如果正确，返回运算结果。</p>
<p>用起来大约这样</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>out<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>exp<span style="color: #339933;">=</span><span style="color: #ff0000;">&quot;2+(1+3)*4&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">double</span> r <span style="color: #339933;">=</span> parse_expr<span style="color: #009900;">&#40;</span>exp<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>out<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>out<span style="color: #339933;">==</span>exp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;parse fail<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s =&gt; %f <span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> exp<span style="color: #339933;">,</span> r<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>回头想下，思路跟<a href="http://github.com/Fleurer/FParser">以前写的parser</a>几乎是葫芦画瓢，也该算是递归下降吧。</p>
<p>代码如下</p>
<p>exp.h</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">double</span> parse_expr<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">double</span> parse_term<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">double</span> parse_fact<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">double</span> parse_numb<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>exp.c</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &quot;exp.h&quot;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// expr ::= term {[+-] term}</span>
<span style="color: #993333;">double</span> parse_expr<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">double</span> r<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>tmp<span style="color: #339933;">,</span> op<span style="color: #339933;">;</span>
    tmp <span style="color: #339933;">=</span> input<span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// factor</span>
    r <span style="color: #339933;">=</span> parse_term<span style="color: #009900;">&#40;</span>tmp<span style="color: #339933;">,</span> output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>output<span style="color: #339933;">==</span>tmp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">// {[+-] term}</span>
    tmp <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>output<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>op<span style="color: #339933;">=*</span>tmp<span style="color: #009900;">&#41;</span><span style="color: #339933;">==</span><span style="color: #ff0000;">'+'</span> <span style="color: #339933;">||</span> op<span style="color: #339933;">==</span><span style="color: #ff0000;">'-'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">double</span> r2 <span style="color: #339933;">=</span> parse_term<span style="color: #009900;">&#40;</span><span style="color: #339933;">++</span>tmp<span style="color: #339933;">,</span> output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>tmp<span style="color: #339933;">==*</span>output<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #339933;">*</span>output <span style="color: #339933;">=</span> input<span style="color: #339933;">;</span>
            <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        r <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>op<span style="color: #339933;">==</span><span style="color: #ff0000;">'+'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">?</span> r<span style="color: #339933;">+</span>r2<span style="color: #339933;">:</span> r<span style="color: #339933;">-</span>r2<span style="color: #339933;">;</span>
        tmp <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>output<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> r<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// term ::= factor {[*/] factor}</span>
<span style="color: #993333;">double</span> parse_term<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">double</span> r<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>tmp<span style="color: #339933;">,</span> op<span style="color: #339933;">;</span>
    tmp <span style="color: #339933;">=</span> input<span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// factor</span>
    r <span style="color: #339933;">=</span> parse_fact<span style="color: #009900;">&#40;</span>tmp<span style="color: #339933;">,</span> output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>output<span style="color: #339933;">==</span>tmp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">// {[*/] factor}</span>
    tmp <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>output<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>op<span style="color: #339933;">=*</span>tmp<span style="color: #009900;">&#41;</span><span style="color: #339933;">==</span><span style="color: #ff0000;">'*'</span> <span style="color: #339933;">||</span> op<span style="color: #339933;">==</span><span style="color: #ff0000;">'/'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">double</span> r2 <span style="color: #339933;">=</span> parse_fact<span style="color: #009900;">&#40;</span><span style="color: #339933;">++</span>tmp<span style="color: #339933;">,</span> output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>tmp<span style="color: #339933;">==*</span>output<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #339933;">*</span>output <span style="color: #339933;">=</span> input<span style="color: #339933;">;</span>
            <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        r <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>op<span style="color: #339933;">==</span><span style="color: #ff0000;">'*'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">?</span> r<span style="color: #339933;">*</span>r2<span style="color: #339933;">:</span> r<span style="color: #339933;">/</span>r2<span style="color: #339933;">;</span>
        tmp <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>output<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> r<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// fact ::= (expr) | numb</span>
<span style="color: #993333;">double</span> parse_fact<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">double</span> r<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>tmp<span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// (expr)</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>input<span style="color: #339933;">==</span><span style="color: #ff0000;">'('</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        tmp <span style="color: #339933;">=</span> input<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        r <span style="color: #339933;">=</span> parse_expr<span style="color: #009900;">&#40;</span>tmp<span style="color: #339933;">,</span> output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">**</span>output<span style="color: #339933;">==</span><span style="color: #ff0000;">')'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>output<span style="color: #009900;">&#41;</span><span style="color: #339933;">++;</span>
            <span style="color: #b1b100;">return</span> r<span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #666666; font-style: italic;">// if fail, output == input</span>
        <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #339933;">*</span>output <span style="color: #339933;">=</span> input<span style="color: #339933;">;</span>
            <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">// numb</span>
    r <span style="color: #339933;">=</span> parse_numb<span style="color: #009900;">&#40;</span>input<span style="color: #339933;">,</span> output<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> r<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">double</span> parse_numb<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>input<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>output<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">double</span>  r <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> ch<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>tmp<span style="color: #339933;">=</span>input<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>ch <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>tmp<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&gt;=</span><span style="color: #ff0000;">'0'</span> <span style="color: #339933;">&amp;&amp;</span> ch<span style="color: #339933;">&lt;=</span><span style="color: #ff0000;">'9'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        r <span style="color: #339933;">=</span> r<span style="color: #339933;">*</span><span style="color: #0000dd;">10</span><span style="color: #339933;">+</span>ch<span style="color: #339933;">-</span><span style="color: #ff0000;">'0'</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #339933;">*</span>output <span style="color: #339933;">=</span> tmp<span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> r<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>main.c</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">double</span> r<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>out<span style="color: #339933;">,</span> exp<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1024</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    scanf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%256s&quot;</span><span style="color: #339933;">,</span> exp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    r <span style="color: #339933;">=</span> parse_expr<span style="color: #009900;">&#40;</span>exp<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>out<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>out<span style="color: #339933;">==</span>exp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;parse fail<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s =&gt; %f <span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> exp<span style="color: #339933;">,</span> r<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/06/30/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e8%af%be%e8%ae%be%ef%bc%8c%e8%a1%a8%e8%be%be%e5%bc%8f%e8%ae%a1%e7%ae%97/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>GCC内联汇编的笔记</title>
		<link>http://www.fleurer-lee.com/2010/06/10/gcc%e5%86%85%e8%81%94%e6%b1%87%e7%bc%96%e7%9a%84%e7%ac%94%e8%ae%b0/</link>
		<comments>http://www.fleurer-lee.com/2010/06/10/gcc%e5%86%85%e8%81%94%e6%b1%87%e7%bc%96%e7%9a%84%e7%ac%94%e8%ae%b0/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 13:38:25 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[笔记]]></category>
		<category><![CDATA[ASM]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645885</guid>
		<description><![CDATA[起比VC风格的内联汇编，GCC的确实要别扭些，一开始要不看手册肯定一头雾水。

int foo = 10, bar = 15;
asm volatile&#40;&#34;addl  %%ebx,%%eax&#34;
            :&#34;=a&#34;&#40;foo&#41;                //output constraint
            :&#34;a&#34;&#40;foo&#41;, &#34;b&#34;&#40;bar&#41;    [...]]]></description>
			<content:encoded><![CDATA[<p>起比VC风格的内联汇编，GCC的确实要别扭些，一开始要不看手册肯定一头雾水。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> foo <span style="color: #339933;">=</span> <span style="color: #0000dd;">10</span><span style="color: #339933;">,</span> bar <span style="color: #339933;">=</span> <span style="color: #0000dd;">15</span><span style="color: #339933;">;</span>
asm <span style="color: #993333;">volatile</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;addl  %%ebx,%%eax&quot;</span>
            <span style="color: #339933;">:</span><span style="color: #ff0000;">&quot;=a&quot;</span><span style="color: #009900;">&#40;</span>foo<span style="color: #009900;">&#41;</span>                <span style="color: #666666; font-style: italic;">//output constraint</span>
            <span style="color: #339933;">:</span><span style="color: #ff0000;">&quot;a&quot;</span><span style="color: #009900;">&#40;</span>foo<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;b&quot;</span><span style="color: #009900;">&#40;</span>bar<span style="color: #009900;">&#41;</span>      <span style="color: #666666; font-style: italic;">//input constraint</span>
            <span style="color: #339933;">:</span>                            <span style="color: #666666; font-style: italic;">//clobbered registers(ignored)</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>指令大家都明白，不过:&#8221;=a&#8221;(foo)这样的语法就古怪了。:后面的东西好像叫做约束，指明了输出和输入中用到的变量和寄存器。第一个的&#8221;=a&#8221;(foo)是输出的约束，就表示汇编执行完毕后foo=a。后面的&#8221;a&#8221;(foo)是输入的约束，表示汇编执行前的a=foo。这一来C和汇编就可以在约束下边交换数据了。</p>
<p>刚才这个a就是表示分配eax寄存器。</p>
<p>各种约束还挺多的&#8230;</p>
<table>
<tr>
<th>a,b,c,d</th>
<th>对应eax,ebx,ecx,edx</th>
</tr>
<tr>
<th>S,D</th>
<th>对应esi,edi</th>
</tr>
<tr>
<th>I</th>
<th>常数</th>
</tr>
<tr>
<th>q</th>
<th>eax,ebx,ecx,edx中静态分配一个</th>
</tr>
<tr>
<th>r</th>
<th>eax,ebx,ecx,edx,esi,edi中静态分配一个</th>
</tr>
<tr>
<th>m</th>
<th>内存定位</th>
</tr>
<tr>
<th>A</th>
<th>同时分配eax和ebx，形成一64位的寄存器</th>
</tr>
<tr>
<th>i</th>
<th>一个编译时确定的立即数。好像ljmp指令的第一个参数就必须得是立即数，比如ljmp $0&#215;80, $label。如果ljmp ax, $label就绘出现一个“Error: suffix or operands invalid for &#8216;ljmp&#8217;的错误”</th>
</tr>
</table>
<p>为什么要这么难看的语法呢&#8230;我猜这东西最早应该是给编译器而不是给人类设计的吧，比起VC风格的内联汇编，它可以得到更多关于变量和寄存器的信息，编译器分配起寄存器来可以心里有数，不用怕自作聪明的人类把事情都搞乱掉。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/06/10/gcc%e5%86%85%e8%81%94%e6%b1%87%e7%bc%96%e7%9a%84%e7%ac%94%e8%ae%b0/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>使用rake编译C程序</title>
		<link>http://www.fleurer-lee.com/2010/05/20/%e4%bd%bf%e7%94%a8rake%e7%bc%96%e8%af%91c%e7%a8%8b%e5%ba%8f/</link>
		<comments>http://www.fleurer-lee.com/2010/05/20/%e4%bd%bf%e7%94%a8rake%e7%bc%96%e8%af%91c%e7%a8%8b%e5%ba%8f/#comments</comments>
		<pubDate>Thu, 20 May 2010 15:11:40 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[备忘]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[rake]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645864</guid>
		<description><![CDATA[每次修改代码一般只会涉及一部分文件，大部分代码都是不必重复编译的。而且编译明显是分步骤也有依赖关系，比如要测试程序就得先链接出一个可执行文件，要链接就得先编译成.o。。。所以就有了make，自动分析任务的依赖关系，只对有变更的文件执行编译，省心省时间。
不过make的语法晦涩啊&#8230;就有了rake
rake提供了file函数可以指明文件的依赖关系，比如：

file 'fdict.o' =&#62; &#91;'src/fdict.c', 'src/fdict.h'&#93; do
  sh 'gcc -Wall -c src/fdict.c'
end
file 'test.o' =&#62; &#91;'src/test.c'&#93; do 
  sh 'gcc -Wall -c src/test.c'
end

file就是个ruby的函数调用，把重复的东西去掉很简单

CFlags = '-Wall'
&#160;
&#91;
  &#91;'src/fdict.c', 'src/fdict.h'&#93;,
  &#91;'src/test.c'&#93;
&#93;.each do &#124;fn_c, *_&#124;
  fn_o = File.basename&#40;fn_c&#41;.ext&#40;'o'&#41;
  file fn_o =&#62; &#91;fn_c, *_&#93; do
    sh &#34;gcc #{CFlags} -c #{fn_c}&#34;
  end
end

再就是链接和执行

OFiles = [...]]]></description>
			<content:encoded><![CDATA[<p>每次修改代码一般只会涉及一部分文件，大部分代码都是不必重复编译的。而且编译明显是分步骤也有依赖关系，比如要测试程序就得先链接出一个可执行文件，要链接就得先编译成.o。。。所以就有了make，自动分析任务的依赖关系，只对有变更的文件执行编译，省心省时间。</p>
<p>不过make的语法晦涩啊&#8230;就有了rake</p>
<p>rake提供了file函数可以指明文件的依赖关系，比如：</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">file <span style="color:#996600;">'fdict.o'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'src/fdict.c'</span>, <span style="color:#996600;">'src/fdict.h'</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  sh <span style="color:#996600;">'gcc -Wall -c src/fdict.c'</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
file <span style="color:#996600;">'test.o'</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'src/test.c'</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#9966CC; font-weight:bold;">do</span> 
  sh <span style="color:#996600;">'gcc -Wall -c src/test.c'</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>file就是个ruby的函数调用，把重复的东西去掉很简单</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">CFlags = <span style="color:#996600;">'-Wall'</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&#91;</span>
  <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'src/fdict.c'</span>, <span style="color:#996600;">'src/fdict.h'</span><span style="color:#006600; font-weight:bold;">&#93;</span>,
  <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'src/test.c'</span><span style="color:#006600; font-weight:bold;">&#93;</span>
<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>fn_c, <span style="color:#006600; font-weight:bold;">*</span>_<span style="color:#006600; font-weight:bold;">|</span>
  fn_o = <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">basename</span><span style="color:#006600; font-weight:bold;">&#40;</span>fn_c<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">ext</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'o'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  file fn_o <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span>fn_c, <span style="color:#006600; font-weight:bold;">*</span>_<span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    sh <span style="color:#996600;">&quot;gcc #{CFlags} -c #{fn_c}&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>再就是链接和执行</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">OFiles = <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">&#123;</span>fdict.<span style="color:#9900CC;">o</span> test.<span style="color:#9900CC;">o</span><span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
task <span style="color:#ff3333; font-weight:bold;">:run</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:link</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#9966CC; font-weight:bold;">do</span> 
  sh <span style="color:#996600;">&quot;./test&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
task <span style="color:#ff3333; font-weight:bold;">:link</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> OFiles <span style="color:#9966CC; font-weight:bold;">do</span>
  sh <span style="color:#996600;">&quot;gcc #{CFlags} #{OFiles.join(' ')} -o test&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>每修改两行C程序到控制台下边一个rake run就可以立即执行，这一来写c就有点像写脚本了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/05/20/%e4%bd%bf%e7%94%a8rake%e7%bc%96%e8%af%91c%e7%a8%8b%e5%ba%8f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于GC的FAQ</title>
		<link>http://www.fleurer-lee.com/2010/03/19/%e5%85%b3%e4%ba%8egc%e7%9a%84faq/</link>
		<comments>http://www.fleurer-lee.com/2010/03/19/%e5%85%b3%e4%ba%8egc%e7%9a%84faq/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 06:13:23 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[翻译]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[GC]]></category>
		<category><![CDATA[MM]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645777</guid>
		<description><![CDATA[翻译：ssword
原文：http://www.iecc.com/gclist/GC-faq.html
这是GC邮件列表的FAQ草稿，欢迎评论、标注或贡献内容。它暂时分为三(?)部分，大约是一般问题，技巧及算法，语言接口和高级论题。以后内容要是多了，这些内容可以重新组织便于查阅。
我们也提供了这些内容的文本文件，即GC-algorithms.txt, GC-lang.txt, and GC-harder.txt。
这里一些内容的学术气可能要差些，而更偏重于传道（或者更确切地说，是在没技术成分有减少的前提下增加点传道的因素）。关于垃圾收集多好多好之类，言辞越简洁越好。
Common questions
常见问题
What is garbage collection?
什么是垃圾收集？
垃圾收集可以是语言运行时的一部分，也可以是个附加库。它们能够与编译器、硬件或操作系统打交道，自动检查出程序中不再使用的内存，并将其回收利用。这也称作“自动存储（内存）回收”。
Why is it good?
它好在哪？
手工内存管理既浪费程序员的生命，也容易引入错误。相当多的程序都难免于内存泄漏，使用了错误处理或线程的程序尤其如此。
未使用过垃圾收集的朋友可能难以察觉它的第二大好处，那就是不必纠结于内存管理的细节（“谁来回收这块内存”），从而简化了程序组件（子程序、库、模块、类）间的接口。
你可以在 Object-Orientation FAQ &#8212; 3.9) Why is Garbage Collection A Good Thing?了解更多内容
Is garbage collection slow?
垃圾收集会不会很慢？
并非如此，现代的垃圾收集器的速度几乎可与手工内存管理(malloc/free或new/delete)相媲美。垃圾收集可能不如特定程序中相应的allocator快，不过为保证手工allocator正常工作而添加的额外代码（如引用计数）往往会使得程序比垃圾收集更慢，共享资源的多线程程序中尤其如此。
正如开始所说，内存已经足够便宜，垃圾收集可以应用到非常大的堆上（比如1GB）。活动内存如果足够的大，暂停时间依然是个问题。不过对于现代的垃圾收集器而言，其暂停时间通常也就0.1秒，对人类的交互几乎可以不计。要是小块活动内存，暂停时间就更少了：0.01秒以下。
Can I use garbage collection with C or C++?
我可以在C\C++中使用垃圾收集吗？
应该可以。对于存在遗留代码的C和C++可能还差些，不过现代的垃圾收集器（测试良好，高效，无暂停）几乎已经支持了一切。了解更多请看GC, C, and C++ 。
Does garbage collection cause my program&#8217;s execution to pause?
垃圾收集会不会让我的程序暂停？
不必。有不一的算法允许垃圾收集并行化、增量化甚至“实时化”。比如C\C++下边就有增量式的垃圾收集。
Where can I get a C or C++ garbage collector?
怎样搞到C\C++的垃圾收集？
Boehm-Weiser collector
http://www.hpl.hp.com/personal/Hans_Boehm/gc/ [...]]]></description>
			<content:encoded><![CDATA[<p>翻译：ssword<br />
原文：http://www.iecc.com/gclist/GC-faq.html</p>
<p>这是GC邮件列表的FAQ草稿，欢迎评论、标注或贡献内容。它暂时分为三(?)部分，大约是一般问题，技巧及算法，语言接口和高级论题。以后内容要是多了，这些内容可以重新组织便于查阅。</p>
<p>我们也提供了这些内容的文本文件，即GC-algorithms.txt, GC-lang.txt, and GC-harder.txt。</p>
<p>这里一些内容的学术气可能要差些，而更偏重于传道（或者更确切地说，是在没技术成分有减少的前提下增加点传道的因素）。关于垃圾收集多好多好之类，言辞越简洁越好。</p>
<p><strong>Common questions<br />
常见问题</strong></p>
<p><strong>What is garbage collection?<br />
什么是垃圾收集？</strong><br />
垃圾收集可以是语言运行时的一部分，也可以是个附加库。它们能够与编译器、硬件或操作系统打交道，自动检查出程序中不再使用的内存，并将其回收利用。这也称作“自动存储（内存）回收”。</p>
<p><strong>Why is it good?<br />
它好在哪？</strong></p>
<p>手工内存管理既浪费程序员的生命，也容易引入错误。相当多的程序都难免于内存泄漏，使用了错误处理或线程的程序尤其如此。</p>
<p>未使用过垃圾收集的朋友可能难以察觉它的第二大好处，那就是不必纠结于内存管理的细节（“谁来回收这块内存”），从而简化了程序组件（子程序、库、模块、类）间的接口。</p>
<p>你可以在 Object-Orientation FAQ &#8212; 3.9) Why is Garbage Collection A Good Thing?了解更多内容</p>
<p><strong>Is garbage collection slow?<br />
垃圾收集会不会很慢？</strong></p>
<p>并非如此，现代的垃圾收集器的速度几乎可与手工内存管理(malloc/free或new/delete)相媲美。垃圾收集可能不如特定程序中相应的allocator快，不过为保证手工allocator正常工作而添加的额外代码（如引用计数）往往会使得程序比垃圾收集更慢，共享资源的多线程程序中尤其如此。</p>
<p>正如开始所说，内存已经足够便宜，垃圾收集可以应用到非常大的堆上（比如1GB）。活动内存如果足够的大，暂停时间依然是个问题。不过对于现代的垃圾收集器而言，其暂停时间通常也就0.1秒，对人类的交互几乎可以不计。要是小块活动内存，暂停时间就更少了：0.01秒以下。</p>
<p><strong>Can I use garbage collection with C or C++?<br />
我可以在C\C++中使用垃圾收集吗？</strong></p>
<p>应该可以。对于存在遗留代码的C和C++可能还差些，不过现代的垃圾收集器（测试良好，高效，无暂停）几乎已经支持了一切。了解更多请看GC, C, and C++ 。</p>
<p><strong>Does garbage collection cause my program&#8217;s execution to pause?<br />
垃圾收集会不会让我的程序暂停？</strong></p>
<p>不必。有不一的算法允许垃圾收集并行化、增量化甚至“实时化”。比如C\C++下边就有增量式的垃圾收集。</p>
<p><strong>Where can I get a C or C++ garbage collector?<br />
怎样搞到C\C++的垃圾收集？</strong></p>
<p>Boehm-Weiser collector<br />
http://www.hpl.hp.com/personal/Hans_Boehm/gc/ or<br />
ftp://parcftp.xerox.com/pub/gc/gc.html<br />
Great Circle from Geodesic Systems  or 800-360-8388 or http://www.geodesic.com<br />
Kevin Warne  or 800-707-7171</p>
<p><strong>Folk myths<br />
坊间传闻</strong></p>
<ul>
<li>GC一定不如手工内存管理快</li>
<li>GC一定会让程序暂停</li>
<li>手工内存管理就不暂停</li>
<li>GC与C\C++水火不容</li>
</ul>
<p><strong>Folk truths<br />
其实…</strong></p>
<ul>
<li>大部分动态创建的对象其实少有与其它对象的关联，通常其引用数就是1。</li>
<li>大部分对象的生存期都很短。</li>
<li>对象大小、生存期呈爆炸式分布，而不是正态分布。</li>
<li>VM很重要</li>
<li>缓存很重要</li>
<li>不成熟的优化乃万恶之源。</li>
</ul>
<p><strong>Tradeoffs<br />
权衡</strong></p>
<ul>
<li>严格式 vs. 保守式</li>
<li>移动/压缩 vs. 无移动</li>
<li>暂停 vs. 增量 vs. 并行</li>
<li>分代 vs. 无分代</li>
</ul>
<p><strong>GC, C, and C++</strong></p>
<p><strong>What do you mean, garbage collection and C?<br />
你说什么，C语言的垃圾收集？</strong></p>
<p>可以引入一个垃圾收集器自动管理内存，从而代替malloc和free的手工申请或释放。通常的做法是将malloc替换为垃圾收集器的allocator，而free则替换为一个空函数。比如X11就是如此。</p>
<p>也可以令free依然生效，不过垃圾收集器就弱化为一个防弹衣的存在，堵住潜在的内存泄漏。这一做法也是有了很多应用，并且工作良好。好处是方便程序员手工管理内存，而程序员顾不到的地方，就交给垃圾收集。这不一定比空free风格的快，不过可能让堆变得小点。</p>
<p><strong>How is this possible?<br />
如何做到的？</strong></p>
<p>C兼容的垃圾收集可以知道指针在什么地方（例如&#8221;bss&#8221;,&#8221;data&#8221;和堆栈里面），保留在堆中的数据结构可以让它们很方便就能找出哪段数据是可能的指针。来个搜索遍历所有可以访问的指针，剩下没被访问的就是垃圾。</p>
<p><strong>This doesn&#8217;t sound very portable. What if I need to port my code and there&#8217;s no garbage collector on the target platform?<br />
这个听起来移植性好像不怎么样。我需要将代码移植到没有垃圾收集器的平台上该怎么办？</strong></p>
<p>有些代码一定是平台相关的，但是大多操作系统都有足够的功能，所以C的垃圾收集其几乎可以在所有平台移植。一般而言，只要有垃圾收集的实现，移植性就不是问题。在Boehm-Weiser的移植还不多的时候，我曾经自己移植过两次，其时我对操作系统的底层接口还不甚熟悉。</p>
<p><strong>Won&#8217;t this leave bugs in my program?<br />
这不会给我程序引入bug吧？</strong></p>
<p>这看你怎么想了。垃圾收集器可以解决程序员的很多问题，从而可以把精力放在其他地方，使得工作完成的更轻松。某种意义上讲，这跟浮点算法和虚拟内存的初衷是一致的。它们被发明出来都是为了解决些折腾程序员的乏味问题（如比例运算、换出页到硬盘）。没有FP和VM支持也可以写代码来实现相应的功能，不过只要有这功能可用，人们就不会自己写。一样的道理。</p>
<p>如果程序中用了垃圾收集风格的代码再扔掉垃圾收集器，内存泄漏的bug是肯定的。同样，如果一个程序用了FP（或VM）相关的代码，再卸掉浮点单元和MMU，bug也是一定的。</p>
<p>实际上，许多使用malloc和free的程序里都有内存泄漏，使用个垃圾收集器反而可以减少程序的bug。这可比手工跟踪内存再手工修复利索多了，要是跟踪发现内存泄漏出在三方库，还根本没办法修复。</p>
<p><strong>Can&#8217;t a devious C programmer break the collector?<br />
程序员可不可以把这收集器玩崩溃?</strong></p>
<p>当然可以。不过大多数人应该更喜欢研究些正事，而不是整天想着把自己的工具玩坏掉。收集器需要正在内存空间中的指针，所以想玩坏就有办法。例如双向链表中的翻转指针技巧就不能用——这指针长得不像指针。如果程序把指针写到文件中，呆会再读出来，没准就崩了，因为这些指针指向的内存很可能已经被回收了。没大有程序会这么玩，所以对大多数程序而言，这不是问题。C中一般的（合法的）指针运算都是没问题的。</p>
<p>某技术团队在考虑使用GC时想到一个问题，那就是使用pointer mangling技巧可能会搞出“不透明”的指针。所谓pointer mangling，就是三方库中的指针与一固定的随机数异或下，这一来三方库中的数据只有按照特定的接口才可以访问。这个不兼容保守式GC，也不兼容Ansi C标准的严格编译&#8230;甚至会迷惑内存泄漏的跟踪器（跟保守式GC用的技术一样）。不过即便如此，它们依然是合法的程序。</p>
<p>Insert more questions here &#8212; send them to</p>
<p><strong>What does a garbage collector do about destructors?<br />
垃圾收集器如何对待析构函数？</strong></p>
<p>析构函数就是对象被释放时候执行的代码，它的用途之一就是来手工回收内存，比如递归地回收对其它对象的引用。垃圾收集器里本没有析构函数的必要：如果一个对象是垃圾，它引用的所有对象就都是垃圾，自然会被收集到。</p>
<p>利用析构函数还可以做点其他事情。有两个应用比较典型：</p>
<p>与外部环境相关的对象的状态。比如文件相关的对象：当一个文件对象被回收时，垃圾收集器应该能保证能够刷新缓冲区、关闭文件，并将文件相关的资源返还给操作系统。</p>
<p>再就是程序需要保留一组在别处引用的对象。程序可能需要知道对象的功能，而不阻止它被收集。</p>
<p>解决这问题有很多方法：</p>
<p>有些系统是“built in”的垃圾收集，它就可以对外部引用的资源有所了解，处理起来也就心里有数<br />
有不少垃圾收集系统有个“弱引用(weak pointer)”的概念，就是不被垃圾收集器认作引用的指针。如果一对象是个弱引用，那么就可以被GC收集。弱引用可以用来实现对象的list之类的数据结构。<br />
再就是，java里可能会这样保护外部资源R：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> ClientR <span style="color: #009900;">&#123;</span>
   CRWeak wr<span style="color: #339933;">;</span>
   <span style="color: #666666; font-style: italic;">// delegate all methods to wr;</span>
   ClientR<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
     wr <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CRWeak<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> CRWeak <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #003399;">WeakReference</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">ReferenceQueue</span> rq <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ReferenceQueue</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #009900;">&#123;</span>
         <span style="color: #003399;">Thread</span> th <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CRCleaner<span style="color: #009900;">&#40;</span>rq<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
         th.<span style="color: #006633;">setDaemon</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
         th.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  CRWeak<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> x<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
     <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span>x, rq<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  ExternalResource r<span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// delegated methods from ClientR</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> CRCleaner <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #003399;">Thread</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003399;">ReferenceQueue</span> rq<span style="color: #339933;">;</span>
  CRCleaner<span style="color: #009900;">&#40;</span><span style="color: #003399;">ReferenceQueue</span> rq<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">rq</span> <span style="color: #339933;">=</span> rq<span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
         <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
           CRWeak x <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>CRWeak<span style="color: #009900;">&#41;</span> rq.<span style="color: #006633;">remove</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
           <span style="color: #666666; font-style: italic;">// Release x.r</span>
         <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>当没有对象引用ClientR时候，这块内存就回收了，而对它的弱引用则移动到了各自的引用队列。清扫线程可以保证这些外部资源的回收。</p>
<p>许多GC系统都有“析构函数”的概念。垃圾收集器在回收一对象的时候，会执行该对象的一个函数来执行必要的清理操作。这会比较复杂，因为有些问题需要考虑：</p>
<ul>
<li>对象是在什么时候才会被收集？它并不像看起来这么简单，这对一些资源吃紧的应用尤为棘手。</li>
<li>析构函数该在哪个线程、资源或者上下文下边执行？</li>
<li>对象的交叉引用该怎么办？</li>
<li>如果一个析构函数使得对象不再是垃圾，又该怎么办？</li>
</ul>
<p><a href="http://www.iecc.com/gclist/GC-faq.html#For%20more%20information"><strong>For more information</strong></a></p>
<p><strong>Contributors (so far)<br />
贡献者（目前）</strong></p>
<p>David Gadbois<br />
Charles Fiterman<br />
David Chase<br />
Marc Shapiro<br />
Kelvin Nilsen<br />
Paul Haahr<br />
Nick Barnes<br />
Pekka P. Pirinen<br />
GC FAQ table of contents<br />
Techniques and algorithms<br />
Language interfaces<br />
Difficult topics<br />
Silly stuff</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/03/19/%e5%85%b3%e4%ba%8egc%e7%9a%84faq/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Fleurer’s Stack VM</title>
		<link>http://www.fleurer-lee.com/2010/02/03/fleurers-stack-vm/</link>
		<comments>http://www.fleurer-lee.com/2010/02/03/fleurers-stack-vm/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 05:09:18 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[备忘]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[fsvm]]></category>
		<category><![CDATA[VM]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645706</guid>
		<description><![CDATA[http://github.com/Fleurer/fsvm
尝试用C写的堆栈机，好像烂尾了 &#8211; -!
只是个运行时，无视了语法分析。随便写的东西也没什么规划，编写的时候就郁闷不知道哪部分该归分析器那部分该归vm，也不知道现有的部分能不能真用到解释器上，于是华丽地烂尾～只实现了20来条指令，可以递归可以闭包，不过不能算乘法&#8230;囧，很简陋啦~ 
好像是第一次写C，不会make就先凑合了rake &#8211; -！ 对C不熟悉，满地的Segmentation Fault对我们只会用printf调试的菜鸟太残酷了&#8230;用了那个保守式的gc库Boehm GC，面对满地的malloc而无free不清楚泄漏起来会怎样&#8230;囧
本来是对C++那套OO无爱，想单用struct和函数也可以OO么。于是用了C，然后就后悔了：我不想重新实现hashmap之类的东西，C++那stl多好&#8230;T_T。倒也找到了个C的泛型库khash，不过宏终究不如模板来的好看&#8230;现在想来，信息学奥赛acm中用C的那些同学做题的时候都是自己实现一遍各个数据结构么？
拿段伪代码：

def main:
     sum&#40;10&#41;
&#160;
def sum&#40;i&#41;:
     if &#40;i==0&#41; : return 0;
     else: return&#40;i+sum&#40;i-1&#41;&#41;;

放到fsvm下大约是这样：

int test_rec&#40;&#41;&#123;
    Op op_main&#91;&#93;=&#123;
        OP_PUSH_NUM, 10, 
        OP_PUSH_CONST, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/Fleurer/fsvm">http://github.com/Fleurer/fsvm</a><br />
尝试用C写的堆栈机，好像烂尾了 &#8211; -!</p>
<p>只是个运行时，无视了语法分析。随便写的东西也没什么规划，编写的时候就郁闷不知道哪部分该归分析器那部分该归vm，也不知道现有的部分能不能真用到解释器上，于是华丽地烂尾～只实现了20来条指令，可以递归可以闭包，不过不能算乘法&#8230;囧，很简陋啦~ </p>
<p>好像是第一次写C，不会make就先凑合了rake &#8211; -！ 对C不熟悉，满地的Segmentation Fault对我们只会用printf调试的菜鸟太残酷了&#8230;用了那个保守式的gc库Boehm GC，面对满地的malloc而无free不清楚泄漏起来会怎样&#8230;囧</p>
<p>本来是对C++那套OO无爱，想单用struct和函数也可以OO么。于是用了C，然后就后悔了：我不想重新实现hashmap之类的东西，C++那stl多好&#8230;T_T。倒也找到了个C的泛型库khash，不过宏终究不如模板来的好看&#8230;现在想来，信息学奥赛acm中用C的那些同学做题的时候都是自己实现一遍各个数据结构么？</p>
<p>拿段伪代码：</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> main:
     <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>:
     <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span>i==<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span> : <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">;</span>
     <span style="color: #ff7700;font-weight:bold;">else</span>: <span style="color: #ff7700;font-weight:bold;">return</span><span style="color: black;">&#40;</span>i+<span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>i-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span></pre></div></div>

<p>放到fsvm下大约是这样：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> test_rec<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    Op op_main<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>
        OP_PUSH_NUM<span style="color: #339933;">,</span> <span style="color: #0000dd;">10</span><span style="color: #339933;">,</span> 
        OP_PUSH_CONST<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//&quot;sum&quot;  </span>
        OP_PUSH_VAR<span style="color: #339933;">,</span> 
        OP_CALL<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
        OP_RET
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    Op op_sum<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span>
        OP_PUSH_CONST<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//&quot;i&quot;</span>
        OP_PUSH_VAR<span style="color: #339933;">,</span> 
        OP_POP_TMP<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//store i</span>
        OP_PUSH_TMP<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//push i</span>
        OP_PUSH_NUM<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> 
        OP_EQ<span style="color: #339933;">,</span>
        OP_NOT<span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// i!=0?</span>
        OP_BRANCH<span style="color: #339933;">,</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">,</span> 
            OP_PUSH_NUM<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
            OP_RET<span style="color: #339933;">,</span>
        <span style="color: #666666; font-style: italic;">//else</span>
            OP_PUSH_TMP<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> 
            OP_PUSH_NUM<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//1</span>
            OP_SUB<span style="color: #339933;">,</span> 
            OP_PUSH_CONST<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//&quot;sum&quot;</span>
            OP_PUSH_VAR<span style="color: #339933;">,</span> 
            OP_CALL<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>   <span style="color: #666666; font-style: italic;">//sum(tmp[0]-1)</span>
            OP_PUSH_TMP<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> 
            OP_PRINT_STACK<span style="color: #339933;">,</span> 
            OP_ADD<span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">//tmp[0]+sum(tmp[0]-1)</span>
        OP_RET
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    Env <span style="color: #339933;">*</span>env<span style="color: #339933;">=</span>fnew_env<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
&nbsp;
    Proto <span style="color: #339933;">*</span>p_main <span style="color: #339933;">=</span> fnew_proto<span style="color: #009900;">&#40;</span>op_main<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    fset_const<span style="color: #009900;">&#40;</span>p_main<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> fstr<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;sum&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    Func<span style="color: #339933;">*</span> f_main<span style="color: #339933;">=</span>fnew_func<span style="color: #009900;">&#40;</span>p_main<span style="color: #339933;">,</span> env<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    Obj o_main<span style="color: #339933;">=</span>ffunc<span style="color: #009900;">&#40;</span>f_main<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    Proto<span style="color: #339933;">*</span> p_sum<span style="color: #339933;">=</span>fnew_proto<span style="color: #009900;">&#40;</span>op_sum<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    fset_const<span style="color: #009900;">&#40;</span>p_sum<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> fstr<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;i&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    fset_const<span style="color: #009900;">&#40;</span>p_sum<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> fstr<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;sum&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    Func<span style="color: #339933;">*</span> f_sum<span style="color: #339933;">=</span>fnew_func<span style="color: #009900;">&#40;</span>p_sum<span style="color: #339933;">,</span> env<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    Obj o_sum<span style="color: #339933;">=</span>ffunc<span style="color: #009900;">&#40;</span>f_sum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    fbind_var<span style="color: #009900;">&#40;</span>env<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;sum&quot;</span><span style="color: #339933;">,</span> o_sum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    fio_puts<span style="color: #009900;">&#40;</span>fcall<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> f_main<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>创建函数的那几个函数我自己也看着别扭&#8230;不过写C还是老实点好 >_<</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/02/03/fleurers-stack-vm/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>C的泛型库khash</title>
		<link>http://www.fleurer-lee.com/2010/01/30/c%e7%9a%84%e6%b3%9b%e5%9e%8b/</link>
		<comments>http://www.fleurer-lee.com/2010/01/30/c%e7%9a%84%e6%b3%9b%e5%9e%8b/#comments</comments>
		<pubDate>Sat, 30 Jan 2010 03:39:43 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[备忘]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[trick]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645695</guid>
		<description><![CDATA[写小东西需要用到哈希表这样的数据结构时候才后悔没用C++，最起码还有stl能用来着。虽说C也能搞泛型，不过宏实现的泛型&#8230;真的好恐怖。
tinyrb用了khash做哈希表，据作者说已经是一个稳定的实现了。
khash.h的内容：
http://attractivechaos.awardspace.com/khash.h.html
大体可以这么用：

#include &#34;stdio.h&#34;
#include &#34;khash.h&#34;
KHASH_MAP_INIT_STR&#40;str, int&#41; //以“str”这名字初始化一个类型的map，键类型为字符串，值类型为int
int main&#40;&#41; &#123;
    int ret, is_missing;
    khiter_t k; //khash的索引器，好像就是个int
    khash_t&#40;str&#41; *h = kh_init&#40;str&#41;; //str只是个名字，初始化
    k = kh_put&#40;str, h, &#34;test&#34;, &#38;ret&#41;; //“test”即键，ret判定操作是否成功，返回k为索引器
&#160;
    if &#40;!ret&#41; kh_del&#40;str, h, k&#41;; //如果h中已经存在了这个键，就删除之
    kh_value&#40;h, k&#41; = 10; //设置键“test”对应的值（10）
&#160;
  [...]]]></description>
			<content:encoded><![CDATA[<p>写小东西需要用到哈希表这样的数据结构时候才后悔没用C++，最起码还有stl能用来着。虽说C也能搞泛型，不过宏实现的泛型&#8230;真的好恐怖。</p>
<p>tinyrb用了khash做哈希表，据作者说已经是一个稳定的实现了。</p>
<p>khash.h的内容：<br />
<a href="http://attractivechaos.awardspace.com/khash.h.html">http://attractivechaos.awardspace.com/khash.h.html</a></p>
<p>大体可以这么用：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &quot;stdio.h&quot;</span>
<span style="color: #339933;">#include &quot;khash.h&quot;</span>
KHASH_MAP_INIT_STR<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> <span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//以“str”这名字初始化一个类型的map，键类型为字符串，值类型为int</span>
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> ret<span style="color: #339933;">,</span> is_missing<span style="color: #339933;">;</span>
    khiter_t k<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//khash的索引器，好像就是个int</span>
    khash_t<span style="color: #009900;">&#40;</span>str<span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span>h <span style="color: #339933;">=</span> kh_init<span style="color: #009900;">&#40;</span>str<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//str只是个名字，初始化</span>
    k <span style="color: #339933;">=</span> kh_put<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> h<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;test&quot;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>ret<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//“test”即键，ret判定操作是否成功，返回k为索引器</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>ret<span style="color: #009900;">&#41;</span> kh_del<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> h<span style="color: #339933;">,</span> k<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//如果h中已经存在了这个键，就删除之</span>
    kh_value<span style="color: #009900;">&#40;</span>h<span style="color: #339933;">,</span> k<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">10</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//设置键“test”对应的值（10）</span>
&nbsp;
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> kh_val<span style="color: #009900;">&#40;</span>h<span style="color: #339933;">,</span>k<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//kh_val(h,k)即10</span>
&nbsp;
    k <span style="color: #339933;">=</span> kh_get<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> h<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;test&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//获得“test”对应的索引器k</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> kh_val<span style="color: #009900;">&#40;</span>h<span style="color: #339933;">,</span>k<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//得10</span>
&nbsp;
    kh_destroy<span style="color: #009900;">&#40;</span>str<span style="color: #339933;">,</span> h<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>终究不如模板来的自然，呵呵~不过也不错了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/01/30/c%e7%9a%84%e6%b3%9b%e5%9e%8b/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>typedef unsigned long VALUE;</title>
		<link>http://www.fleurer-lee.com/2010/01/19/typedef-unsigned-long-value/</link>
		<comments>http://www.fleurer-lee.com/2010/01/19/typedef-unsigned-long-value/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 08:38:24 +0000</pubDate>
		<dc:creator>fleurer</dc:creator>
				<category><![CDATA[笔记]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[VM]]></category>

		<guid isPermaLink="false">http://www.fleurer-lee.com/?p=645669</guid>
		<description><![CDATA[因为swdpress.cn的死掉严重打击积极性，好久没更新了。此文纯凑数。
ruby中除了Fixnum，其余所有类型的值都是引用传递。读《ruby hacking guide》时看到如下的定义：

typedef unsigned long VALUE;

同lua那union+tag不一样，ruby中所有类型的值都存放在一个VALUE中，而没有tag指明其类型。如果是Fixnum，就把数值直接放在VALUE里；如果是其它类型，则存放其地址（unsigned long和C中指针类型的长度一致）。不过万一作为Fixnum的VALUE指向的地址与其他对象有重叠怎么办？它又怎么区别数值和地址呢？
这用到了一点tricks，C的struct在内存中都是以4字节对齐，因此ruby中所有对象的地址都偶数。在表示Fixnum时，ruby就将C的int值左移一位再加一，使其看起来总是个奇数，这样就不会与ruby的其它对象有重叠。

 123  #define INT2FIX(i) ((VALUE)(((long)(i))&#60;&#60;1 &#124; FIXNUM_FLAG))
 122  #define FIXNUM_FLAG 0x01
&#40;ruby.h&#41;

判断一个VALUE是Fixnum还是地址，只需判断VALUE是奇数还是偶数就行了。
表示true,false和nil是这样：

 164  #define Qfalse 0        /* Ruby's false */
 165  #define Qtrue  2        /* Ruby's true */
 166  #define [...]]]></description>
			<content:encoded><![CDATA[<p>因为swdpress.cn的死掉严重打击积极性，好久没更新了。此文纯凑数。</p>
<p>ruby中除了Fixnum，其余所有类型的值都是引用传递。读《<a href="http://code.google.com/p/rhgchs/">ruby hacking guide</a>》时看到如下的定义：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">typedef</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">long</span> VALUE<span style="color: #339933;">;</span></pre></div></div>

<p>同lua那union+tag不一样，ruby中所有类型的值都存放在一个VALUE中，而没有tag指明其类型。如果是Fixnum，就把数值直接放在VALUE里；如果是其它类型，则存放其地址（unsigned long和C中指针类型的长度一致）。不过万一作为Fixnum的VALUE指向的地址与其他对象有重叠怎么办？它又怎么区别数值和地址呢？</p>
<p>这用到了一点tricks，C的struct在内存中都是以4字节对齐，因此ruby中所有对象的地址都偶数。在表示Fixnum时，ruby就将C的int值左移一位再加一，使其看起来总是个奇数，这样就不会与ruby的其它对象有重叠。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"> <span style="color: #0000dd;">123</span>  <span style="color: #339933;">#define INT2FIX(i) ((VALUE)(((long)(i))&lt;&lt;1 | FIXNUM_FLAG))</span>
 <span style="color: #0000dd;">122</span>  <span style="color: #339933;">#define FIXNUM_FLAG 0x01</span>
<span style="color: #009900;">&#40;</span>ruby.<span style="color: #202020;">h</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>判断一个VALUE是Fixnum还是地址，只需判断VALUE是奇数还是偶数就行了。</p>
<p>表示true,false和nil是这样：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"> <span style="color: #0000dd;">164</span>  <span style="color: #339933;">#define Qfalse 0        /* Ruby's false */</span>
 <span style="color: #0000dd;">165</span>  <span style="color: #339933;">#define Qtrue  2        /* Ruby's true */</span>
 <span style="color: #0000dd;">166</span>  <span style="color: #339933;">#define Qnil   4        /* Ruby's nil */</span>
<span style="color: #009900;">&#40;</span>ruby.<span style="color: #202020;">h</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>都是偶数。像刚才说的，它们不会被当作是地址了么？这就用到了另一个trick：进程虚拟地址空间的前一部分都是不可访问的。因而0,2,4的地址上不会存在ruby对象。</p>
<p>PS: 感谢FX大大提醒，这套方法有个标准的名字叫做“tagged pointer” :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2010/01/19/typedef-unsigned-long-value/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>缪论：C最高效</title>
		<link>http://www.fleurer-lee.com/2009/09/08/%e7%bc%aa%e8%ae%ba%ef%bc%9ac%e6%9c%80%e9%ab%98%e6%95%88/</link>
		<comments>http://www.fleurer-lee.com/2009/09/08/%e7%bc%aa%e8%ae%ba%ef%bc%9ac%e6%9c%80%e9%ab%98%e6%95%88/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 00:54:06 +0000</pubDate>
		<dc:creator>ssword</dc:creator>
				<category><![CDATA[翻译]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[PL]]></category>

		<guid isPermaLink="false">http://swdpress.cn/?p=645455</guid>
		<description><![CDATA[作者：Mark Chu-Carroll (aka MarkCC)
翻译：ssword
原文：http://scienceblogs.com/goodmath/2006/11/the_c_is_efficient_language_fa.php

昨天偶然看到一篇关于程序设计语言的文章，直击我G点，忍不住前来吐槽。这篇文章来自greythumb.org，叫做《程序员的呼喊：C\C++该有什么》。
无非也就是“C\C++是追求高效的首选”之类的老生常谈。他们错了。它们不是。C\C++接近硬件是为了直接控制堆栈、修改寄存器等等，而非为了高效。在科研编程或者数值计算的应用上，它们差劲得很。
贴一段让我崩溃的文字：
首先，那些担忧纯属多余。C\C++永远不会消失。为什么？因为有无数的程序现在是、永远都是吃CPU的。对这些领域的编程而言，根本没有快过C\C++的语言。将来会不会出现这种语言？我非常怀疑。
我说的这些领域就是：科学计算、游戏/物理特效、光线跟踪、实时3D图像、音频处理、编译器、高速路由、进化计算(我的最爱:)，还有高级语言运行时&#8212;毫无疑问。再就是像操作系统、硬件驱动之类“接近底层”，需要很多交互、甚至内嵌汇编的程序。C就是简单版的汇编，这就是为何C总是作为此类程序的首选。
对这些领域而言，在语言及架构层面的过早优化是可以接受、有时甚至是必须的。我敢打赌，在五十年后，这些领域的一部分依然会是C\C++或者相似语言的天下。对于同样一个基于进化计算指令集的实现，C要整整快过java两倍。由此你可以看出C是多么的快。
问题在这里：C\C++在数值计算上的性能相当扯淡。它们不是最快的，而且绝非偶然。实际上，受底层实现的一些限制，使得C\C++根本不可能表现得很高效。这便是为什么到今天依然有Fortan应用于在高精度科研项目，而这些应用往往需要榨干机器的每一滴性能&#8212;&#8212;如流体动力学模拟。[1]
程序要高效离不开编译器优化，现代架构的编译器可以达到人类优化汇编代码的极限。有时交换两条无关指令的顺序就可以得到一个出人意料的性能提升，而机器所做的优化，很多都是人类难以企及的。[2]
因此对于现代的开发而言，程序的高效绝非只凭程序员一人之力。程序员需要做的，是仔细选择合适的算法&#8212;&#8211;这活机器做不了；机器需要做的，是仔细地调整指令、约束流水线、内存延时等等。二者合作才会有高效的程序。二者的工作又是相互影响的：程序员应该用机器能够理解的代码来描述算法，以方便机器进行优化。
这就是C\C++失败的地方。C\C++在语义上过度依赖指针，导致不受约束的指针几乎无处不在。在C\C++中，并没有真正意义上的数组&#8212;&#8212;它们只是指针，下标只是指针运算的简写形式（C\C++里的x[n]与*(x+n)是完全一样的）。
过度依赖指针就意味着，C\C++的编译器会很难辨认两个东西是否独立。由此产生的问题被称作“重名探测”（alias detection），也就是找出可能指向同一个位置的两个变量。若存在不受约束的指针，别名探测几乎就无法实现。举个例子：

for &#40;int i=0; i &#60; 20000&#41; &#123;
   for &#40;int j=0; j &#60; 20000&#41; &#123;
      x&#91;i&#93;&#91;j&#93; = y&#91;i-2&#93;&#91;j+1&#93; * y&#91;i+1&#93;&#91;j-2&#93;;
   &#125;
&#125;

看下这个循环。它可以并行化或向量化[3]，但前提必须是x与y没有重合、完全无关，这在C\C++中这根没办法得到保证。Fortran-77就没问题，你可以轻而易举地检查它俩是否不同。若是Fortran-98，你还可以检查出它们是否为指针，若有需要，程序就可以弄清楚它们之间是否有重复。在C\C++下，这就做不到（Fortran也不是最好的&#8212;&#8212;一门来自Lawrence Livermore labs 的实验语言Sisal，在特定代码上要强过Fortran 20%）。
这个例子是拿并行说事，但“重名”带来的问题可不只并行这么简单，说并行只是因为比较好解释。“重名”带来的问题直接影响了C\C++代码的编写。
再举个具体的例子吧，我就不吐槽了。六年前，我在一个项目里需要实现一个相当复杂的算法来计算两个数组的“最长公共串”（longest comon sequence， LCS）。计算LCS的标准算法被称作“动态规划”，是O*(n^3) 的时间，O(n^2) 的空间。搞计算生物学的人们也有个相似的算法，时间与它相同，不过空间平均起来只有O(n)。
我不知道该用哪门语言，就做了个实验。我用C，C++，ocaml，java和python分别实现了一遍LCS算法，来比对代码的复杂度
以及运行效率。2000个元素的数组来做实验数据，所得的测试结果如下：

C: 0.8 seconds.
C++: 2.3 seconds.
OCaml: 0.6 seconds interpreted, 0.3 seconds fully compiled.
Java: 1 minute [...]]]></description>
			<content:encoded><![CDATA[<p>作者：Mark Chu-Carroll (aka MarkCC)<br />
翻译：ssword<br />
原文：<a href="http://scienceblogs.com/goodmath/2006/11/the_c_is_efficient_language_fa.php">http://scienceblogs.com/goodmath/2006/11/the_c_is_efficient_language_fa.php</a></p>
<hr />
<p>昨天偶然看到一篇关于程序设计语言的文章，直击我G点，忍不住前来吐槽。这篇文章来自greythumb.org，叫做《程序员的呼喊：C\C++该有什么》。</p>
<p>无非也就是“C\C++是追求高效的首选”之类的老生常谈。他们错了。它们不是。C\C++接近硬件是为了直接控制堆栈、修改寄存器等等，而非为了高效。在科研编程或者数值计算的应用上，它们差劲得很。</p>
<p>贴一段让我崩溃的文字：</p>
<blockquote><p>首先，那些担忧纯属多余。C\C++永远不会消失。为什么？因为有无数的程序现在是、永远都是吃CPU的。对这些领域的编程而言，根本没有快过C\C++的语言。将来会不会出现这种语言？我非常怀疑。</p>
<p>我说的这些领域就是：科学计算、游戏/物理特效、光线跟踪、实时3D图像、音频处理、编译器、高速路由、进化计算(我的最爱:)，还有高级语言运行时&#8212;毫无疑问。再就是像操作系统、硬件驱动之类“接近底层”，需要很多交互、甚至内嵌汇编的程序。C就是简单版的汇编，这就是为何C总是作为此类程序的首选。</p>
<p>对这些领域而言，在语言及架构层面的过早优化是可以接受、有时甚至是必须的。我敢打赌，在五十年后，这些领域的一部分依然会是C\C++或者相似语言的天下。对于同样一个基于进化计算指令集的实现，C要整整快过java两倍。由此你可以看出C是多么的快。</p></blockquote>
<p>问题在这里：C\C++在数值计算上的性能相当扯淡。它们不是最快的，而且绝非偶然。实际上，受底层实现的一些限制，使得C\C++根本不可能表现得很高效。这便是为什么到今天依然有Fortan应用于在高精度科研项目，而这些应用往往需要榨干机器的每一滴性能&#8212;&#8212;如流体动力学模拟。[<a href="#q1">1</a>]</p>
<p>程序要高效离不开编译器优化，现代架构的编译器可以达到人类优化汇编代码的极限。有时交换两条无关指令的顺序就可以得到一个出人意料的性能提升，而机器所做的优化，很多都是人类难以企及的。[<a href="#q2">2</a>]</p>
<p>因此对于现代的开发而言，程序的高效绝非只凭程序员一人之力。程序员需要做的，是仔细选择合适的算法&#8212;&#8211;这活机器做不了；机器需要做的，是仔细地调整指令、约束流水线、内存延时等等。二者合作才会有高效的程序。二者的工作又是相互影响的：程序员应该用机器能够理解的代码来描述算法，以方便机器进行优化。</p>
<p>这就是C\C++失败的地方。C\C++在语义上过度依赖指针，导致不受约束的指针几乎无处不在。在C\C++中，并没有真正意义上的数组&#8212;&#8212;它们只是指针，下标只是指针运算的简写形式（C\C++里的x[n]与*(x+n)是完全一样的）。</p>
<p>过度依赖指针就意味着，C\C++的编译器会很难辨认两个东西是否独立。由此产生的问题被称作“重名探测”（alias detection），也就是找出可能指向同一个位置的两个变量。若存在不受约束的指针，别名探测几乎就无法实现。举个例子：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">20000</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> j<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> j <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">20000</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      x<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> y<span style="color: #009900;">&#91;</span>i<span style="color: #339933;">-</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> y<span style="color: #009900;">&#91;</span>i<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #339933;">-</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>看下这个循环。它可以并行化或向量化[<a href="#q3">3</a>]，但前提必须是x与y没有重合、完全无关，这在C\C++中这根没办法得到保证。Fortran-77就没问题，你可以轻而易举地检查它俩是否不同。若是Fortran-98，你还可以检查出它们是否为指针，若有需要，程序就可以弄清楚它们之间是否有重复。在C\C++下，这就做不到（Fortran也不是最好的&#8212;&#8212;一门来自Lawrence Livermore labs 的实验语言Sisal，在特定代码上要强过Fortran 20%）。</p>
<p>这个例子是拿并行说事，但“重名”带来的问题可不只并行这么简单，说并行只是因为比较好解释。“重名”带来的问题直接影响了C\C++代码的编写。</p>
<p>再举个具体的例子吧，我就不吐槽了。六年前，我在一个项目里需要实现一个相当复杂的算法来计算两个数组的“最长公共串”（longest comon sequence， LCS）。计算LCS的标准算法被称作“动态规划”，是O*(n^3) 的时间，O(n^2) 的空间。搞计算生物学的人们也有个相似的算法，时间与它相同，不过空间平均起来只有O(n)。</p>
<p>我不知道该用哪门语言，就做了个实验。我用C，C++，ocaml，java和python分别实现了一遍LCS算法，来比对代码的复杂度<br />
以及运行效率。2000个元素的数组来做实验数据，所得的测试结果如下：</p>
<ul>
<li>C: 0.8 seconds.</li>
<li>C++: 2.3 seconds.</li>
<li>OCaml: 0.6 seconds interpreted, 0.3 seconds fully compiled.</li>
<li>Java: 1 minute 20 seconds.</li>
<li>Python: over 5 minutes.</li>
</ul>
<p>一年以后，我用新版本的JIT再次测试，java的时间减少到了0.7秒，外加1秒的JVM初始化。（C\C++以及ocaml的初始化时间几乎可以忽略不计）</p>
<p>Objective-Caml字节码解释器的执行效率比经过仔细优化的C程序还要高！为什么？因为Ocaml编译器可以辨别出两个数组的无关性&#8212;&#8212;这一来就不必担心循环中的一个迭代会影响到另一个迭代中的值。C编译器可做的优化就要少得多了，因为它无法辨认这些优化是否会影响到程序的正常运行。</p>
<p>不只没有赋值的函数式语言，不那么高效的高级语言在一些方面的性能也要比C\C++出色。CMU Common Lisp在数值计算上就比C\C++强。几年前有个论文写了这个：在一台Sun Sparc工作站上，如果你带上类型声明，用vector（Lisp的数组）和赋值来实现的科学计算/数值计算Lisp代码，要比经过Solaris C或gcc最大优化的C算法实现更加高效。</p>
<hr />
<p>译者注：<br />
<a name="q1"></a>[1] 从一开始Fortran就被设计成可以进行高度优化的语言…Fortran的设计者关注的是科学计算中代码的运行时性能…在这样想法的指导下，只有当Fortran编译器生成的代码性能是有经验的程序员手写的并经过性能调整的汇编代码性能的两倍时，Fortran语言才会被用户接受。 &#8212;&#8212;J.Backus《the history of Fortran I , II, III》<br />
C最初被设计成有类型的汇编语言，重点针对可用性，而非优化。 &#8212;&#8212;《现代体系结构的优化编译器》 p147</p>
<p><a name="q2"></a>[2] 为此就需要对指令重新排列，或成为调度，以使相互冲突或依赖的指令在时间上分离，这种需要也就是为现代处理器做编译器特别困难的主要原因之一。 &#8212;&#8212;-《程序设计语言：实践之路》 p207</p>
<p><a name="q3"></a>[3] 向量化就是将一个循环中的迭代并行执行。<br />
例如：<br />
For I  in  1 to 100<br />
    A[i]=i*2<br />
End<br />
其中的a[1]和a[2]可以同时执行，前提就是循环中的每个迭代不会相互影响。古代有种机器貌似叫做向量计算机，里面的循环都是并行执行的，就是比较早的并行计算的大型机了。</p>
<hr />
<p>ps:<br />
作者原文上的评论是相当的长，应了那句“凡语言贴，必火”。 毕竟没有银弹，要了解一个东西也应该了解它的弱点，不然就容易为你爱的东西所束缚。</p>
<p>不过作者貌似回避了一点，那就是所谓“科学计算、游戏/物理特效、光线跟踪、实时3D图像、音频处理、编译器、高速路由、进化计算，还有高级语言运行时”等等，在实际中还是C用的多。“C是接近硬件，而不是为了高效”，不过游戏、音频等方面还有个东西叫做硬件加速哇。对于C在优化上的限制，可以参考《现代体系结构的优化编译器》 418页，上面举的例子可能要更好，说明也更详细，也有一整章C编译器在优化上的解决方法。</p>
<p>pps: 很明显，第一段翻译的很不妥..求正解</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fleurer-lee.com/2009/09/08/%e7%bc%aa%e8%ae%ba%ef%bc%9ac%e6%9c%80%e9%ab%98%e6%95%88/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
