<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title></title>
    <description></description>
    <link>http://meizhini.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
          <item>
        <title>python_GC内存出问题了的法宝</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/249716" style="color:red;">http://meizhini.javaeye.com/blog/249716</a>&nbsp;
          发表时间: 2008年10月07日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Python的内存泄漏及gc模块的使用<br />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- 6.11日错误修正版<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Horin|贺勤<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Email: horin153@msn.com<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Blog: http://blog.csdn.net/horin153/<br /><br />&nbsp;&nbsp;&nbsp; 在 Python 中，为了解决内存泄漏问题，采用了对象引用计数，并基于引用计数实现自动垃圾回收。<br />&nbsp;&nbsp;&nbsp; 因为 Python 有了自动垃圾回收功能，不少初学者就认为自己从此过上了好日子，不必再受内存泄漏的骚扰了。但如果查看一下 Python 文档对 __del__() 函数的描述，就知道好日子里也是有阴云的。下面摘抄一点文档内容：<br />&nbsp;&nbsp;&nbsp; Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects (e.g., a doubly-linked list or a tree data structure with parent and child pointers); a reference to the object on the stack frame of a function that caught an exception (the traceback stored in sys.exc_traceback keeps the stack frame alive); or a reference to the object on the stack frame that raised an unhandled exception in interactive mode (the traceback stored in sys.last_traceback keeps the stack frame alive).<br />&nbsp;&nbsp;&nbsp; 可见，有 __del__() 函数的对象间的循环引用是导致内存泄漏的主凶。特别说明：对没有 __del__() 函数的 Python 对象间的循环引用，是可以被自动垃圾回收掉的。<br /><br />&nbsp;&nbsp;&nbsp; 如何知道一个对象是否内存泄漏了呢？<br />&nbsp;&nbsp;&nbsp; 方法一、当你认为一个对象应该被销毁时（即引用计数为 0），可以通过 sys.getrefcount(obj) 来获取对象的引用计数，并根据返回值是否为 0 来判断是否内存泄漏。如果返回的引用计数不为 0，说明在此刻对象 obj 是不能被垃圾回收器回收掉的。<br />&nbsp;&nbsp;&nbsp; 方法二、也可以通过 Python 扩展模块 gc 来查看不能回收的对象的详细信息。<br /><br /><br />&nbsp;&nbsp;&nbsp; 首先，来看一段正常的测试代码：<br /><br />#--------------- code begin --------------<br /><br /># -*- coding: utf-8 -*-<br /><br />import gc<br />import sys<br /><br />class CGcLeak(object):<br />&nbsp;&nbsp;&nbsp; def __init__(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._text = '#'*10<br /><br />&nbsp;&nbsp;&nbsp; def __del__(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pass<br /><br />def make_circle_ref():<br />&nbsp;&nbsp;&nbsp; _gcleak = CGcLeak()<br />#&nbsp;&nbsp; _gcleak._self = _gcleak # test_code_1<br />&nbsp;&nbsp;&nbsp; print '_gcleak ref count0:%d' % sys.getrefcount(_gcleak)<br />&nbsp;&nbsp;&nbsp; del _gcleak<br />&nbsp;&nbsp;&nbsp; try:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print '_gcleak ref count1:%d' % sys.getrefcount(_gcleak)<br />&nbsp;&nbsp;&nbsp; except UnboundLocalError:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print '_gcleak is invalid!'<br /><br />def test_gcleak():<br />&nbsp;&nbsp;&nbsp; # Enable automatic garbage collection.<br />&nbsp;&nbsp;&nbsp; gc.enable()<br />&nbsp;&nbsp;&nbsp; # Set the garbage collection debugging flags.<br />&nbsp;&nbsp;&nbsp; gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | \<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)<br /><br />&nbsp;&nbsp;&nbsp; print 'begin leak test...'<br />&nbsp;&nbsp;&nbsp; make_circle_ref()<br /><br />&nbsp;&nbsp;&nbsp; print 'begin collect...'<br />&nbsp;&nbsp;&nbsp; _unreachable = gc.collect()<br />&nbsp;&nbsp;&nbsp; print 'unreachable object num:%d' % _unreachable<br />&nbsp;&nbsp;&nbsp; print 'garbage object num:%d' % len(gc.garbage)<br /><br />if __name__ == '__main__':<br />&nbsp;&nbsp;&nbsp; test_gcleak()<br /><br />#--------------- code end ----------------<br /><br />&nbsp;&nbsp;&nbsp; 在 test_gcleak() 中，设置垃圾回收器调试标志后，再用 collect() 进行垃圾回收，最后打印出该次垃圾回收发现的不可达的垃圾对象数和整个解释器中的垃圾对象数。<br /><br />&nbsp;&nbsp;&nbsp; gc.garbage 是一个 list 对象，列表项是垃圾收集器发现的不可达（即是垃圾对象）、但又不能释放（即不能回收）的对象。文档描述为：A list of objects which the collector found to be unreachable but could not be freed (uncollectable objects).<br />&nbsp;&nbsp;&nbsp; 通常，gc.garbage 中的对象是引用环中的对象。因为 Python 不知道按照什么样的安全次序来调用环中对象的 __del__() 函数，导致对象始终存活在 gc.garbage 中，造成内存泄漏。如果知道一个安全的次序，那么就打破引用环，再执行 del gc.garbage[:] ，以清空垃圾对象列表。<br /><br />&nbsp;&nbsp;&nbsp; 上段代码输出为（#后字符串为笔者所加注释）：<br />#-----------------------------------------<br />begin leak test...<br /># 变量 _gcleak 的引用计数为 2.<br />_gcleak ref count0:2<br /># _gcleak 变为不可达(unreachable)的非法变量.<br />_gcleak is invalid!<br /># 开始垃圾回收<br />begin collect...<br /># 本次垃圾回收发现的不可达的垃圾对象数为 0.<br />unreachable object num:0<br /># 整个解释器中的垃圾对象数为 0.<br />garbage object num:0<br />#-----------------------------------------<br />&nbsp;&nbsp;&nbsp; 可见 _gcleak 对象的引用计数是正确的，也没有任何对象发生内存泄漏。<br /><br />&nbsp;&nbsp;&nbsp; 如果不注释掉 make_circle_ref() 中的 test_code_1 语句：<br />&nbsp;&nbsp;&nbsp; _gcleak._self = _gcleak<br />也就是让 _gcleak 形成一个自己对自己的循环引用。再运行上述代码，输出结果就变成：<br />#-----------------------------------------<br />begin leak test...<br />_gcleak ref count0:3<br />_gcleak is invalid!<br />begin collect...<br /># 发现可以回收的垃圾对象: 地址为 012AA090，类型为 CGcLeak.<br />gc: uncollectable &lt;CGcLeak 012AA090&gt;<br />gc: uncollectable &lt;dict 012AC1E0&gt;<br />unreachable object num:2<br />#!! 不能回收的垃圾对象数为 1，导致内存泄漏！<br />garbage object num:1<br />#-----------------------------------------<br />&nbsp;&nbsp;&nbsp; 可见 &lt;CGcLeak 012AA090&gt; 对象发生了内存泄漏！！而多出的 dict 垃圾就是泄漏的 _gcleak 对象的字典，打印出字典信息为:<br />{'_self': &lt;__main__.CGcLeak object at 0x012AA090&gt;, '_text': '##########'}<br /><br />&nbsp;&nbsp;&nbsp; 除了对自己的循环引用，多个对象间的循环引用也会导致内存泄漏。简单举例如下：<br /><br />#--------------- code begin --------------<br /><br />class CGcLeakA(object):<br />&nbsp;&nbsp;&nbsp; def __init__(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._text = '#'*10<br /><br />&nbsp;&nbsp;&nbsp; def __del__(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pass<br /><br />class CGcLeakB(object):<br />&nbsp;&nbsp;&nbsp; def __init__(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._text = '*'*10<br /><br />&nbsp;&nbsp;&nbsp; def __del__(self):<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pass<br /><br />def make_circle_ref():<br />&nbsp;&nbsp;&nbsp; _a = CGcLeakA()<br />&nbsp;&nbsp;&nbsp; _b = CGcLeakB()<br />&nbsp;&nbsp;&nbsp; _a._b = _b&nbsp; # test_code_2<br />&nbsp;&nbsp;&nbsp; _b._a = _a&nbsp; # test_code_3<br />&nbsp;&nbsp;&nbsp; print 'ref count0:a=%d b=%d' % \<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (sys.getrefcount(_a), sys.getrefcount(_b))<br />#&nbsp;&nbsp; _b._a = None&nbsp;&nbsp;&nbsp; # test_code_4<br />&nbsp;&nbsp;&nbsp; del _a<br />&nbsp;&nbsp;&nbsp; del _b<br />&nbsp;&nbsp;&nbsp; try:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'ref count1:a=%d' % sys.getrefcount(_a)<br />&nbsp;&nbsp;&nbsp; except UnboundLocalError:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print '_a is invalid!'<br />&nbsp;&nbsp;&nbsp; try:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'ref count2:b=%d' % sys.getrefcount(_b)<br />&nbsp;&nbsp;&nbsp; except UnboundLocalError:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print '_b is invalid!'<br /><br />#--------------- code end ----------------<br /><br />&nbsp;&nbsp;&nbsp; 这次测试后输出结果为：<br />#-----------------------------------------<br />begin leak test...<br />ref count0:a=3 b=3<br />_a is invalid!<br />_b is invalid!<br />begin collect...<br />gc: uncollectable &lt;CGcLeakA 012AA110&gt;<br />gc: uncollectable &lt;CGcLeakB 012AA0B0&gt;<br />gc: uncollectable &lt;dict 012AC1E0&gt;<br />gc: uncollectable &lt;dict 012AC0C0&gt;<br />unreachable object num:4<br />garbage object num:2<br />#-----------------------------------------<br />可见 _a,_b 对象都发生了内存泄漏。因为二者是循环引用，垃圾回收器不知道该如何回收，也就是不知道该首先调用那个对象的 __del__() 函数。<br /><br />&nbsp;&nbsp;&nbsp; 采用以下任一方法，打破环状引用，就可以避免内存泄漏：<br />[1] 注释掉 make_circle_ref() 中的 test_code_2 语句；<br />[2] 注释掉 make_circle_ref() 中的 test_code_3 语句；<br />[3] 取消对 make_circle_ref() 中的 test_code_4 语句的注释。<br />相应输出结果变为：<br />#-----------------------------------------<br />begin leak test...<br />ref count0:a=2 b=3&nbsp; # 注：此处输出结果视情况变化.<br />_a is invalid!<br />_b is invalid!<br />begin collect...<br />unreachable object num:0<br />garbage object num:0<br />#-----------------------------------------<br /><br /><br />&nbsp;&nbsp;&nbsp; 结论：Python 的 gc 有比较强的功能，比如设置 gc.set_debug(gc.DEBUG_LEAK) 就可以进行循环引用导致的内存泄露的检查。如果在开发时进行内存泄露检查；在发布时能够确保不会内存泄露，那么就可以延长 Python 的垃圾回收时间间隔、甚至主动关闭垃圾回收机制，从而提高运行效率。<br /><br /><br />推荐阅读文献<br /><br />1, Python垃圾回收算法描述,http://wiki.woodpecker.org.cn/moin/python_ref_circle_gc<br />2, Garbage Collection for Python,http://arctrix.com/nas/python/gc/</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/249716#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 07 Oct 2008 10:35:34 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/249716</link>
        <guid>http://meizhini.javaeye.com/blog/249716</guid>
      </item>
          <item>
        <title>gdb的使用</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/249415" style="color:red;">http://meizhini.javaeye.com/blog/249415</a>&nbsp;
          发表时间: 2008年10月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>内容： <br /><br />编译 <br />运行 gdb <br />调试会话示例 <br />使用断点 <br />更多断点和观察点 <br />Core 文件 <br />堆栈跟踪 <br />连接到其它进程 <br />其它小技巧 <br />结束语 <br />参考资料 <br />关于作者 <br /><br />GNU 调试器简介 <br />作者:David Seager <br /><br /><br />Linux 的大部分特色源自于 shell 的 GNU 调试器，也称作 gdb。gdb 可以让您查看程序的内部结构、打印变量值、设置断点，以及单步调试源代码。它是功能极其强大的工具，适用于修复程序代码中的问题。在本文中，我将尝试说明 gdb 有多棒，多实用。 <br /><br />编译 <br />开始调试之前，必须用程序中的调试信息编译要调试的程序。这样，gdb 才能够调试所使用的变量、代码行和函数。如果要进行编译，请在 gcc（或 g++）下使用额外的 '-g' 选项来编译程序： <br /><br />gcc -g eg.c -o eg <br /><br />运行 gdb <br />在 shell 中，可以使用 'gdb' 命令并指定程序名作为参数来运行 gdb，例如 'gdb eg'；或者在 gdb 中，可以使用 file 命令来装入要调试的程序，例如 'file eg'。这两种方式都假设您是在包含程序的目录中执行命令。装入程序之后，可以用 gdb 命令 'run' 来启动程序。 <br /><br />调试会话示例 <br />如果一切正常，程序将执行到结束，此时 gdb 将重新获得控制。但如果有错误将会怎么样？这种情况下，gdb 会获得控制并中断程序，从而可以让您检查所有事物的状态，如果运气好的话，可以找出原因。为了引发这种情况，我们将使用一个示例程序： <br /><br />代码示例 eg1.c <br />#include <br /><br />int wib(int no1, int no2) <br />{ <br />int result, diff; <br />diff = no1 - no2; <br />result = no1 / diff; <br />return result; <br />} <br /><br />int main(int argc, char *argv[]) <br />{ <br />int value, div, result, i, total; <br /><br />value = 10; <br />div = 6; <br />total = 0; <br /><br />for(i = 0; i &lt; 10; i++) <br />{ <br />result = wib(value, div); <br />total += result; <br />div++; <br />value--; <br />} <br /><br />printf("%d wibed by %d equals %dn", value, div, total); <br />return 0; <br />} <br /><br /><br /><br /><br />这个程序将运行 10 次 for 循环，使用 'wib()' 函数计算出累积值，最后打印出结果。 <br /><br />在您喜欢的文本编辑器中输入这个程序（要保持相同的行距），保存为 'eg1.c'，使用 'gcc -g eg1.c -o eg1' 进行编译，并用 'gdb eg1' 启动 gdb。使用 'run' 运行程序可能会产生以下消息： <br /><br /><br />Program received signal SIGFPE, Arithmetic exception. <br />0x80483ea in wib (no1=8, no2=8) at eg1.c:7 <br />7 result = no1 / diff; <br />(gdb) <br /><br /><br /><br />gdb 指出在程序第 7 行发生一个算术异常，通常它会打印这一行以及 wib() 函数的自变量值。要查看第 7 行前后的源代码，请使用 'list' 命令，它通常会打印 10 行。再次输入 'list'（或者按回车重复上一条命令）将列出程序的下 10 行。从 gdb 消息中可以看出，第 7 行中的除法运算出了错，程序在这一行中将变量 "no1" 除以 "diff"。 <br /><br />要查看变量的值，使用 gdb 'print' 命令并指定变量名。输入 'print no1' 和 'print diff'，可以相应看到 "no1" 和 "diff" 的值，结果如下： <br /><br /><br />(gdb) print no1 <br />$5 = 8 <br />(gdb) print diff <br />$2 = 0 <br /><br /><br /><br />gdb 指出 "no1" 等于 8，"diff" 等于 0。根据这些值和第 7 行中的语句，我们可以推断出算术异常是由除数为 0 的除法运算造成的。清单显示了第 6 行计算的变量 "diff"，我们可以打印 "diff" 表达式（使用 'print no1 - no2' 命令），来重新估计这个变量。gdb 告诉我们 wib 函数的这两个自变量都等于 8，于是我们要检查调用 wib() 函数的 main() 函数，以查看这是在什么时候发生的。在允许程序自然终止的同时，我们使用 'continue' 命令告诉 gdb 继续执行。 <br /><br /><br />(gdb) continue <br />Continuing. <br /><br />Program terminated with signal SIGFPE, Arithmetic exception. <br />The program no longer exists. <br /><br /><br /><br />使用断点 <br />为了查看在 main() 中发生了什么情况，可以在程序代码中的某一特定行或函数中设置断点，这样 gdb 会在遇到断点时中断执行。可以使用命令 'break main' 在进入 main() 函数时设置断点，或者可以指定其它任何感兴趣的函数名来设置断点。然而，我们只希望在调用 wib() 函数之前中断执行。输入 'list main' 将打印从 main() 函数开始的源码清单，再次按回车将显示第 21 行上的 wib() 函数调用。要在那一行上设置断点，只需输入 'break 21'。gdb 将发出以下响应： <br /><br /><br />(gdb) break 21 <br />Breakpoint 1 at 0x8048428: file eg1.c, line 21. <br /><br /><br /><br />以显示它已在我们请求的行上设置了 1 号断点。'run' 命令将从头重新运行程序，直到 gdb 中断为止。发生这种情况时，gdb 会生成一条消息，指出它在哪个断点上中断，以及程序运行到何处： <br /><br /><br />Breakpoint 1, main (argc=1, argv=0xbffff954) at eg1.c:21 <br />21 result = wib(value, div); <br /><br /><br /><br />发出 'print value' 和 'print div' 将会显示在第一次调用 wib() 时，变量分别等于 10 和 6，而 'print i' 将会显示 0。幸好，gdb 将显示所有局部变量的值，并使用 'info locals' 命令保存大量输入信息。 <br /><br />从以上的调查中可以看出，当 "value" 和 "div" 相等时就会出现问题，因此输入 'continue' 继续执行，直到下一次遇到 1 号断点。对于这次迭代，'info locals' 显示了 value=9 和 div=7。 <br /><br />与其再次继续，还不如使用 'next' 命令单步调试程序，以查看 "value" 和 "div" 是如何改变的。gdb 将响应： <br /><br /><br />(gdb) next <br />22 total += result; <br /><br /><br /><br />再按两次回车将显示加法和减法表达式： <br /><br /><br />(gdb) <br />23 div++; <br />(gdb) <br />24 value--; <br /><br /><br /><br />再按两次回车将显示第 21 行，wib() 调用。'info locals' 将显示目前 "div" 等于 "value"，这就意味着将发生问题。如果有兴趣，可以使用 'step' 命令（与 'next' 形成对比，'next' 将跳过函数调用）来继续执行 wib() 函数，以再次查看除法错误，然后使用 'next' 来计算 "result"。 <br /><br />现在已完成了调试，可以使用 'quit' 命令退出 gdb。由于程序仍在运行，这个操作会终止它，gdb 将提示您确认。 <br /><br />更多断点和观察点 <br />由于我们想要知道在调用 wib() 函数之前 "value" 什么时候等于 "div"，因此在上一示例中我们在第 21 行中设置断点。我们必须继续执行两次程序才会发生这种情况，但是只要在断点上设置一个条件就可以使 gdb 只在 "value" 与 "div" 真正相等时暂停。要设置条件，可以在定义断点时指定 "break if "。将 eg1 再次装入 gdb，并输入： <br /><br /><br />(gdb) break 21 if value==div <br />Breakpoint 1 at 0x8048428: file eg1.c, line 21. <br /><br /><br /><br />如果已经在第 21 行中设置了断点，如 1 号断点，则可以使用 'condition' 命令来代替在断点上设置条件： <br /><br /><br />(gdb) condition 1 value==div <br /><br /><br /><br />使用 'run' 运行 eg1.c 时，如果 "value" 等于 "div"，gdb 将中断，从而避免了在它们相等之前必须手工执行 'continue'。调试 C 程序时，断点条件可以是任何有效的 C 表达式，一定要是程序所使用语言的任意有效表达式。条件中指定的变量必须在设置了断点的行中，否则表达式就没有什么意义！ <br /><br />使用 'condition' 命令时，如果指定断点编号但又不指定表达式，可以将断点设置成无条件断点，例如，'condition 1' 就将 1 号断点设置成无条件断点。 <br /><br />要查看当前定义了什么断点及其条件，请发出命令 'info break'： <br /><br /><br />(gdb) info break <br />Num Type Disp Enb Address What <br />1 breakpoint keep y 0x08048428 in main at eg1.c:21 <br />stop only if value == div <br />breakpoint already hit 1 time <br /><br /><br /><br />除了所有条件和已经遇到断点多少次之外，断点信息还在 'Enb' 列中指定了是否启用该断点。可以使用命令 'disable '、'enable ' 或 'delete ' 来禁用、启用和彻底删除断点，例如 'disable 1' 将阻止在 1 号断点处中断。 <br /><br />如果我们对 "value" 什么时候变得与 "div" 相等更感兴趣，那么可以使用另一种断点，称作监视。当指定表达式的值改变时，监视点将中断程序执行，但必须在表达式中所使用的变量在作用域中时设置监视点。要获取作用域中的 "value" 和 "div"，可以在 main 函数上设置断点，然后运行程序，当遇到 main() 断点时设置监视点。重新启动 gdb，并装入 eg1，然后输入： <br /><br /><br />(gdb) break main <br />Breakpoint 1 at 0x8048402: file eg1.c, line 15. <br />(gdb) run <br />... <br />Breakpoint 1, main (argc=1, argv=0xbffff954) at eg1.c:15 <br />15 value = 10; <br /><br /><br /><br />要了解 "div" 何时更改，可以使用 'watch div'，但由于要在 "div" 等于 "value" 时中断，那么应输入： <br /><br /><br />(gdb) watch div==value <br />Hardware watchpoint 2: div == value <br /><br /><br /><br />如果继续执行，那么当表达式 "div==value" 的值从 0（假）变成 1（真）时，gdb 将中断： <br /><br /><br />(gdb) continue <br />Continuing. <br />Hardware watchpoint 2: div == value <br /><br />Old value = 0 <br />New value = 1 <br />main (argc=1, argv=0xbffff954) at eg1.c:19 <br />19 for(i = 0; i &lt; 10; i++) <br /><br /><br /><br />'info locals' 命令将验证 "value" 是否确实等于 "div"（再次声明，是 8）。 <br /><br />'info watch' 命令将列出已定义的监视点和断点（此命令等价于 'info break'），而且可以使用与断点相同的语法来启用、禁用和删除监视点。 <br /><br />core 文件 <br />在 gdb 下运行程序可以使俘获错误变得更容易，但在调试器外运行的程序通常会中止而只留下一个 core 文件。gdb 可以装入 core 文件，并让您检查程序中止之前的状态。 <br /><br />在 gdb 外运行示例程序 eg1 将会导致核心信息转储： <br /><br />$ ./eg1 <br />Floating point exception (core dumped) <br /><br /><br /><br />要使用 core 文件启动 gdb，在 shell 中发出命令 'gdb eg1 core' 或 'gdb eg1 -c core'。gdb 将装入 core 文件，eg1 的程序清单，显示程序是如何终止的，并显示非常类似于我们刚才在 gdb 下运行程序时看到的消息： <br /><br /><br />... <br />Core was generated by `./eg1'. <br />Program terminated with signal 8, Floating point exception. <br />... <br />#0 0x80483ea in wib (no1=8, no2=8) at eg1.c:7 <br />7 result = no1 / diff; <br /><br /><br /><br />此时，可以发出 'info locals'、'print'、'info args' 和 'list' 命令来查看引起除数为零的值。'info variables' 命令将打印出所有程序变量的值，但这要进行很长时间，因为 gdb 将打印 C 库和程序代码中的变量。为了更容易地查明在调用 wib() 的函数中发生了什么情况，可以使用 gdb 的堆栈命令。 <br /><br />堆栈跟踪 <br />程序&ldquo;调用堆栈&rdquo;是当前函数之前的所有已调用函数的列表（包括当前函数）。每个函数及其变量都被分配了一个&ldquo;帧&rdquo;，最近调用的函数在 0 号帧中（&ldquo;底部&rdquo;帧）。要打印堆栈，发出命令 'bt'（'backtrace' [回溯] 的缩写）： <br /><br /><br />(gdb) bt <br />#0 0x80483ea in wib (no1=8, no2=8) at eg1.c:7 <br />#1 0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21 <br /><br /><br /><br />此结果显示了在 main() 的第 21 行中调用了函数 wib()（只要使用 'list 21' 就能证实这一点），而且 wib() 在 0 号帧中，main() 在 1 号帧中。由于 wib() 在 0 号帧中，那么它就是执行程序时发生算术错误的函数。 <br /><br />实际上，发出 'info locals' 命令时，gdb 会打印出当前帧中的局部变量，缺省情况下，这个帧中的函数就是被中断的函数（0 号帧）。可以使用命令 'frame' 打印当前帧。要查看 main 函数（在 1 号帧中）中的变量，可以发出 'frame 1' 切换到 1 号帧，然后发出 'info locals' 命令： <br /><br /><br />(gdb) frame 1 <br />#1 0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21 <br />21 result = wib(value, div); <br />(gdb) info locals <br />value = 8 <br />div = 8 <br />result = 4 <br />i = 2 <br />total = 6 <br /><br /><br /><br />此信息显示了在第三次执行 "for" 循环时（i 等于 2）发生了错误，此时 "value" 等于 "div"。 <br /><br />可以通过如上所示在 'frame' 命令中明确指定号码，或者使用 'up' 命令在堆栈中上移以及 'down' 命令在堆栈中下移来切换帧。要获取有关帧的进一步信息，如它的地址和程序语言，可以使用命令 'info frame'。 <br /><br />gdb 堆栈命令可以在程序执行期间使用，也可以在 core 文件中使用，因此对于复杂的程序，可以在程序运行时跟踪它是如何转到函数的。 <br /><br />连接到其它进程 <br />除了调试 core 文件或程序之外，gdb 还可以连接到已经运行的进程（它的程序已经过编译，并加入了调试信息），并中断该进程。只需用希望 gdb 连接的进程标识替换 core 文件名就可以执行此操作。以下是一个执行循环并睡眠的示例程序： <br /><br />eg2 示例代码 <br />#include <br />int main(int argc, char *argv[]) <br />{ <br />int i; <br />for(i = 0; i &lt; 60; i++) <br />{ <br />sleep(1); <br />} <br /><br />return 0; <br />} <br /><br /><br /><br /><br />使用 'gcc -g eg2.c -o eg2' 编译该程序并使用 './eg2 &amp;' 运行该程序。请留意在启动该程序时在背景上打印的进程标识，在本例中是 1283： <br /><br />./eg2 &amp; <br />[3] 1283 <br /><br /><br /><br />启动 gdb 并指定进程标识，在我举的这个例子中是 'gdb eg2 1283'。gdb 会查找一个叫作 "1283" 的 core 文件。如果没有找到，那么只要进程 1283 正在运行（在本例中可能在 sleep() 中），gdb 就会连接并中断该进程： <br /><br /><br />... <br />/home/seager/gdb/1283: No such file or directory. <br />Attaching to program: /home/seager/gdb/eg2, Pid 1283 <br />... <br />0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6 <br />(gdb) <br /><br /><br /><br />此时，可以发出所有常用 gdb 命令。可以使用 'backtrace' 来查看当前位置与 main() 的相对关系，以及 mian() 的帧号是什么，然后切换到 main() 所在的帧，查看已经在 "for" 循环中运行了多少次： <br /><br />(gdb) backtrace <br />#0 0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6 <br />#1 0x400a877d in __sleep (seconds=1) at ../sysdeps/unix/sysv/linux/sleep.c:78 <br />#2 0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7 <br />(gdb) frame 2 <br />#2 0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7 <br />7 sleep(1); <br />(gdb) print i <br />$1 = 50 <br /><br /><br /><br />如果已经完成了对程序的修改，可以 'detach' 命令继续执行程序，或者 'kill' 命令杀死进程。还可以首先使用 'file eg2' 装入文件，然后发出 'attach 1283' 命令连接到进程标识 1283 下的 eg2。 <br /><br />其它小技巧 <br />gdb 可以让您通过使用 shell 命令在不退出调试环境的情况下运行 shell 命令，调用形式是 'shell [commandline]'，这有助于在调试时更改源代码。 <br /><br />最后，在程序运行时，可以使用 'set ' 命令修改变量的值。在 gdb 下再次运行 eg1，使用命令 'break 7 if diff==0' 在第 7 行（将在此处计算结果）设置条件断点，然后运行程序。当 gdb 中断执行时，可以将 "diff" 设置成非零值，使程序继续运行直至结束： <br /><br /><br />Breakpoint 1, wib (no1=8, no2=8) at eg1.c:7 <br />7 result = no1 / diff; <br />(gdb) print diff <br />$1 = 0 <br />(gdb) set diff=1 <br />(gdb) continue <br />Continuing. <br />0 wibed by 16 equals 10 <br /><br />Program exited normally. <br /><br /><br /><br />结束语 <br />GNU 调试器是所有程序员工具库中的一个功能非常强大的工具。在本文中，我只介绍了 gdb 的一小部分功能。要了解更多知识，建议您阅读 GNU 调试器手册。 <br /><br />参考资料 <br /><br />GNU 调试器手册 <br />调试会话示例的源代码。 <br />连接示例的源代码。 <br /><br />关于作者 <br /><br />David Seager 是 IBM 的软件开发人员，他从事 Linux 和基于 Web 的应用工作已有两年时间了。 <br /><br />转自:IBM developerWorks中国网站</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/249415#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 06 Oct 2008 15:23:38 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/249415</link>
        <guid>http://meizhini.javaeye.com/blog/249415</guid>
      </item>
          <item>
        <title>调试日志:备忘录</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/249412" style="color:red;">http://meizhini.javaeye.com/blog/249412</a>&nbsp;
          发表时间: 2008年10月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>调试工具收集:</p>
<p>&nbsp;</p>
<p>gdb ./run_name</p>
<p>backtrace:</p>
<p>查看调用函数</p>
<p>区别下strace.</p>
<p>strace是用来查看其他的运行情况.例如: strace make.</p>
<p>&nbsp;</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/249412#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 06 Oct 2008 15:19:02 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/249412</link>
        <guid>http://meizhini.javaeye.com/blog/249412</guid>
      </item>
          <item>
        <title>内存泄漏</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/249402" style="color:red;">http://meizhini.javaeye.com/blog/249402</a>&nbsp;
          发表时间: 2008年10月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>网络上有很多&lt;浅谈C/C++内存泄漏及其检测工具&gt;.</p>
<p>我:特别感兴趣的是:</p>
<p>一个工具:<span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">BoundsChecker</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"></span></p>
<p>一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的，大小任意的（内存块的大小可以在程序运行期决定），使用完后必须显示释放的内存。应用程序一般使用malloc，realloc，new等函数从堆中分配到一块内存，使用完后，程序必须负责相应的调用free或delete释放该内存块，否则，这块内存就不能被再次使用，我们就说这块内存泄漏了。以下这段小程序演示了堆内存发生泄漏的情形： </p>
<pre class="wiki">void MyFunction(int nSize)
{
　char* p= new char[nSize];
　if( !GetStringFrom( p, nSize ) ){
　　MessageBox(“Error”);
　　return;
　}
　…//using the string pointed by p;
　delete p;
} 
</pre>
<p>&nbsp;</p>
<p>内存泄漏的发生方式： </p>
<p>　　以发生的方式来分类，内存泄漏可以分为4类： </p>
<p>　　1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到，每次被执行的时候都会导致一块内存泄漏。比如例二，如果Something()函数一直返回True，那么pOldBmp指向的HBITMAP对象总是发生泄漏。 </p>
<p>　　2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。比如例二，如果Something()函数只有在特定环境下才返回True，那么pOldBmp指向的HBITMAP对象并不总是发生泄漏。常发性和偶发性是相对的。对于特定的环境，偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。 </p>
<p>　　3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次，或者由于算法上的缺陷，导致总会有一块仅且一块内存发生泄漏。比如，在类的构造函数中分配内存，在析构函数中却没有释放该内存，但是因为这个类是一个Singleton，所以内存泄漏只会发生一次。另一个例子： </p>
<pre class="wiki">char* g_lpszFileName = NULL;

void SetFileName( const char* lpcszFileName )
{
　if( g_lpszFileName ){
　　free( g_lpszFileName );
　}
　g_lpszFileName = strdup( lpcszFileName );
} 
</pre>
<p>　　例三 </p>
<p>　　如果程序在结束的时候没有释放g_lpszFileName指向的字符串，那么，即使多次调用<a href="http://meizhini.javaeye.com/prj/tech/wiki/SetFileName" class="missing wiki" rel="nofollow">SetFileName?</a>()，总会有一块内存，而且仅有一块内存发生泄漏。 </p>
<p>　　4. 隐式内存泄漏。程序在运行过程中不停的分配内存，但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏，因为最终程序释放了所有申请的内存。但是对于一个服务器程序，需要运行几天，几周甚至几个月，不及时释放内存也可能导致最终耗尽系统的所有内存。所以，我们称这类内存泄漏为隐式内存泄漏。举一个例子：</p>
<pre class="wiki">class Connection
{
　public:
　　Connection( SOCKET s);
　　~Connection();
　　…
　private:
　　SOCKET _socket;
　　…
};

class ConnectionManager
{
　public:
　　ConnectionManager(){}
　　~ConnectionManager(){
　　　list::iterator it;
　　　for( it = _connlist.begin(); it != _connlist.end(); ++it ){
　　　　delete （*it）;
　　　}
　　　_connlist.clear();
　　}
　　void OnClientConnected( SOCKET s ){
　　　Connection* p = new Connection(s);
　　　_connlist.push_back(p);
　　}
　　void OnClientDisconnected( Connection* pconn ){
　　　_connlist.remove( pconn );
　　　delete pconn;
　　}
　private:
　　list _connlist;
}; 
</pre>
<p>　　例四 </p>
<p>　　假设在Client从Server端断开后，Server并没有呼叫<a href="http://meizhini.javaeye.com/prj/tech/wiki/OnClientDisconnected" class="missing wiki" rel="nofollow">OnClientDisconnected?</a>()函数，那么代表那次连接的Connection对象就不会被及时的删除（在Server程序退出的时候，所有Connection对象会在<a href="http://meizhini.javaeye.com/prj/tech/wiki/ConnectionManager" class="missing wiki" rel="nofollow">ConnectionManager?</a>的析构函数里被删除）。当不断的有连接建立、断开时隐式内存泄漏就发生了。 </p>
<p>　　从用户使用程序的角度来看，内存泄漏本身不会产生什么危害，作为一般的用户，根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积，这会最终消耗尽系统所有的内存。从这个角度来说，一次性内存泄漏并没有什么危害，因为它不会堆积，而隐式内存泄漏危害性则非常大，因为较之于常发性和偶发性内存泄漏它更难被检测到。</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/249402#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 06 Oct 2008 15:10:12 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/249402</link>
        <guid>http://meizhini.javaeye.com/blog/249402</guid>
      </item>
          <item>
        <title>BoundsChecker</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/249401" style="color:red;">http://meizhini.javaeye.com/blog/249401</a>&nbsp;
          发表时间: 2008年10月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><a href="http://blog.csdn.net/daijunhua/archive/2008/05/28/2489211.aspx">http://blog.csdn.net/daijunhua/archive/2008/05/28/2489211.aspx</a></p>
<p>&nbsp;</p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">BoundsChecker 是一个Run-Time错误检测工具，它主要定位程序在运行时期发生的各种错误。BoundsChecker能检测的错误包括：</span></span></p>
<p style="text-indent: -21pt;"><span style="font-size: 16px;"><span style="font-weight: normal;">1)</span><span style="font-weight: normal;">)1、</span><span style="font-weight: normal;">指针操作和内存、资源泄露错误，比如：</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">内存泄露；</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">资源泄露；</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">对指针变量的错误操作。</span></span></p>
<p style="text-indent: -10.5pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">22、内存操作方面的错误，比如：</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">&nbsp;&nbsp;内存读、写溢出；</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">&nbsp;&nbsp;使用未初始化的内存。</span></span></p>
<p style="text-indent: -10.5pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">33、API函数使用错误</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">BoundsChecker安装成功后，在你的VC++集成开发环境中，会多出了一个名为BoundsChecker的菜单，如下所示：</span></span></p>
<p style="text-indent: 21pt; text-align: center;"><span style="font-size: 16px;"><img src="http://www.testage.net/AutoTest/UploadFiles/200604/20060416155607543.jpg" border="0" height="430" alt="1.jpg" width="307" /><br /></span></p>
<p align="center" style="text-align: center;"><span style="font-size: 16px;"><span style="font-weight: normal;">图3-1 BoundsChecker在</span><span style="font-weight: normal;">VC++集成开发环境</span><span style="font-weight: normal;">中添加的菜单</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">BoundsChecker 已经非常完好的集成到VC++集成开发环境中了。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-size: 16px;"><span style="font-weight: normal;">使用</span><span style="font-weight: normal;">BoundsChecker对程序的运行时错误进行检测，有两种使用模式可供选择。一种模式叫做ActiveCheck，一种模式叫做FinalCheck</span><span style="font-weight: normal;">。下面分别进行介绍。</span></span></p>
<p style="text-indent: 21pt;">&nbsp;</p>
<h2><a name="_Toc28658273"><span><span style="font-size: 16px;"><span style="text-decoration: underline;">3.1 ActiveCheck</span></span></span></a></h2>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">ActiveCheck是BoundsChecker提供的一种方便、快捷的错误检测模式，它能检测的错误种类有限，只包括：内存泄露错误、资源泄露错误、API函数使用错误。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">要想使用ActiveCheck模式来检测程序的运行时错误，只需在VC++集成开发环境中打开BoundsChecker功能，然后从调试状态运行程序即可。此时ActiveCheck会在后台自动运行，随时检测程序是否发生了错误。下面说一下具体的使用步骤。</span></span></p>
<h3><a name="_Toc28658274"><span><span style="font-size: 16px;"><span style="text-decoration: underline;">3．1．1 用ActiveCheck来检测错误</span></span></span></a></h3>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">使用ActiveCheck的具体的操作步骤如下：</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">首先，在VC++集成开发环境中打开你要对其进行<strong class="kgb" onmouseover="isShowAds = false;isShowAds2 = false;isShowGg = true;InTextAds_GgLayer=&quot;_u6D4B_u8BD5&quot;;KeyGate_ads.ShowGgAds(this,&quot;_u6D4B_u8BD5&quot;,event)" onclick="window.open(&quot;http://www.google.com/url?sa=L&amp;ai=Bdq6HuXfuRpDwGqXmsAL2vuTyDKbqjjGS3dOJA7O0-IIBgITMAhAEGAQg-dr4BygFOAFQtcvq9_j_____AWCdwduBzAWqAQoxMDAwMDA4MDAxyAEBgAIBqQLhneLmv9iBPsgC6p-FA9kDP1v4XpRyK_Q&amp;num=4&amp;q=http://www.happyway.com.cn/&amp;usg=AFQjCNE0RUc4kwqFDIQQCD8G77I97fVRiA&quot;);GgKwClickStat(&quot;测试&quot;,&quot;www.happyway.com.cn&quot;,&quot;afs&quot;,&quot;1000008001&quot;);" onmouseout="isShowGg = false;InTextAds_GgLayer=&quot;_u6D4B_u8BD5&quot;" style="font-weight: normal; margin: 0px; color: #0000ff; text-decoration: underline; border-width: 0px; padding: 0px;">测试</strong>的程序，同时保证项目处于Debug编译状态下。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">其次，确保VC++集成开发环境中[BoundsChecker/Integrated Debugging]菜单项和[BoundsChecker/Report Errors and Events]菜单项处于被选中的状态。只有这两项被选中，BoundsChecker才会在程序运行过程中发挥作用。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">最后，在VC++集成开发环境中选择[Build/ Start Debug/Go]菜单命令，在Debug状态下运行程序，ActiveCheck也在后台开始运行了。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">这时，就可以按照制定好的测试用例，对程序进行操作。凡是程序执行过的代码，如果存在错误，ActiveCheck就会记录下来。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">有一个地方要说一下，在[BoundsChecker]菜单中有一项[Report Errors Immediately]，如下图所示：</span></span></p>
<div style="text-align: center;"><span style="font-size: 16px;"><img src="http://www.testage.net/AutoTest/UploadFiles/200604/20060416155609775.jpg" border="0" height="431" alt="2.jpg" width="304" /><br /></span>
<p align="center" style="text-indent: 21pt; text-align: center;"><span style="font-size: 16px;"><span style="font-weight: normal;">图3-2 关于</span><span style="font-weight: normal;">[BoundsChecker / Report Errors Immediately] 菜单项</span></span></p>
<p align="left" style="text-indent: 21pt; text-align: left;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">该菜单项对于</span><span><span style="font-size: 16px;">ActiveCheck 模式，以及下面就要介绍的FinalCheck模式的作用是一样的，即：如果不选中该项，则BoundsChecker会记录程序运行过程中发现的各种错误，直到程序结束后再进行报告；当选中该菜单项时，在程序的运行过程中，一旦BoundsChecker发现错误，会马上弹出如下的对话框进行提示：<br /></span></span></span></p>
<p style="text-indent: 21pt; text-align: center;"><span style="font-size: 16px;"><img src="http://www.testage.net/AutoTest/UploadFiles/200604/20060416155610699.jpg" border="0" height="226" alt="3.jpg" style="width: 512px;" width="512" /><br /></span></p>
<p align="left" style="text-indent: 21pt; text-align: left;">&nbsp;</p>
<p align="center" style="margin-left: 18pt; text-align: center;"><span style="font-size: 16px;"><span style="font-weight: normal;">图3-3 错误报告对话框</span></span></p>
<p align="left" style="margin-left: 17.85pt; text-align: left;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">下面按图中标注的数字序号解释一下对话框中各个按钮的功能：</span></span></p>
<p align="left" style="margin-left: 17.85pt; text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮</span><span style="font-weight: normal;">1：点击</span><span style="font-weight: normal;">该按钮，则表示先暂时不理会这个错误，继续执行程序。</span></span></p>
<p align="left" style="margin-left: 18pt; text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮2：</span><span style="font-weight: normal;">点击</span><span style="font-weight: normal;">该按钮，则会马上跳转到出现问题的代码行处。处理完问题后，点击</span><span style="font-weight: normal;">[Build/ Start Debug/Go]菜单项，</span><span style="font-weight: normal;">可以继续执行程序，进行检测。</span></span></p>
<p align="left" style="margin-left: 18pt; text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮3：</span><span style="font-weight: normal;">点击</span><span style="font-weight: normal;">该按钮，则将该错误添加到被忽略的错误列表中去，当再次出现这个问题时，</span><span style="font-weight: normal;">BoundsChecker将不会进行报告。</span></span></p>
<p align="left" style="margin-left: 18pt; text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮4：</span><span style="font-weight: normal;">点击</span><span style="font-weight: normal;">该按钮，则立即终止程序的执行。</span></span></p>
<p align="left" style="margin-left: 18pt; text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮5：</span><span style="font-weight: normal;">点击</span><span style="font-weight: normal;">该按钮，会显示当前内存的申请、使用情况。</span></span></p>
<p align="left" style="margin-left: 18pt; text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮6：</span><span style="font-weight: normal;">点击</span><span style="font-weight: normal;">该按钮，会得到当前这个错误的帮助信息。</span></span></p>
<p align="left" style="margin-left: 18pt; text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮7、8： 这两个按钮与[</span><span style="font-weight: normal;">BoundsChecker\Report Errors Immediately</span><span style="font-weight: normal;">]和[</span><span style="font-weight: normal;">BoundsChecker\ Report Errors and Event</span><span style="font-weight: normal;">] 菜单命令的功能是完全一样的，</span><span style="font-weight: normal;">在此不再赘述。</span></span></p>
<p align="left" style="text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">按钮9：</span><span style="font-weight: normal;">点击</span><span style="font-weight: normal;">该按钮，会显示/隐藏与该错误有关的函数调用堆栈情况，以及具体的出错代码行的位置。</span></span></p>
<p align="left" style="text-indent: 21pt; text-align: left;"><span style="font-size: 16px;"><span style="font-weight: normal;">是否选中[BoundsChecker／Report Errors Immediately]菜单项，完全取决于你自己的喜好，以及测试时的具体情况。如果你想要</span><span style="font-weight: normal;">BoundsChecker在程序运行过程中实时向你汇报发现的错误，那么你就选中这个菜单项；如果想等到操作结束后，再对操作过程中BoundsChecker发现的错误统一进行分析，就不必选中这个菜单项。我在平常使用过程中更偏向于使用后一种。</span></span></p>
<h3 style="text-align: left;"><a name="_Toc28658275"><span><span style="font-size: 16px; color: #000000;"><span style="text-decoration: underline;">3．1．2 分析错误</span></span></span></a></h3>
<div style="text-align: left;"></div>
<p style="text-indent: 21pt; text-align: left;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">在你操作全部结束，退出程序后，</span></span></p>
<p style="text-align: left;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">BoundsChecker 会显示一个所发现错误的列表。我们需要对列表中罗列的错误进行分析，来确定错误的原因和位置。</span></span></p>
<p style="text-indent: 21pt; text-align: left;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">在错误检测结果列表中，罗列出了在程序的执行过程中ActiveCheck检测到的所有的内存泄露、资源泄露和API函数使用错误的相关信息。如下图所示：</span></span></p>
<p style="text-indent: 21pt; text-align: left;">&nbsp;</p>
<div style="text-align: center;"><span style="font-size: 16px;"><img src="http://www.testage.net/AutoTest/UploadFiles/200604/20060416155610950.jpg" border="0" height="211" alt="4.jpg" style="width: 512px;" width="512" /><br /></span></div>
<p style="text-indent: 21pt; text-align: left;">&nbsp;</p>
<p align="center" style="text-align: center;"><span style="font-size: 16px;">图3-4 <span style="font-size: 10.5pt;">错误检测结果</span></span></p>
<div style="text-align: left;">
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">在左边的窗口中，逐条列出了程序在内存、资源、API 函数使用上的问题，包括：该问题的种类，该问题发生的次数，如果是内存泄露，损失了多少内存，以及发生该问题的代码位置等等。当你用鼠标单击选中某一条记录时，在右边的窗口中会显示出与该条错误记录相对应的函数调用堆栈情况。当你用鼠标双击某一条错误记录时，会定位到引发该错误的源代码处。</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">好了，BoundsChecker在ActiveCheck模式下的使用方法至此介绍完了，是不是很简单？</span></span></p>
<p style="text-indent: 21pt;"><span style="font-size: 16px;"><span style="font-weight: normal;">在ActiveCheck模式下检测程序时，程序的运行速度基本不受影响，但其缺点是检测的错误种类有限，即只能检查出</span><span style="font-weight: normal;">内存泄露错误、资源泄露错误、API函数使用错误。</span><span style="font-weight: normal;">BoundsChecker 提供了另外一种检测错误的模式&mdash;&mdash; FinalCheck，也就是我们在前面提到的BoundsChecker的第二种使用模式。 FinalCheck可以检测出程序中更多的错误。下面我们就对它进行介绍。</span></span></p>
<h2><a name="_Toc28658276"><span><span style="font-size: 16px; color: #000000;"><span style="text-decoration: underline;">3．2 用 FinalCheck检测更多的错误</span></span></span></a></h2>
<p style="text-indent: 21pt;"><span style="font-size: 16px;"><span style="font-weight: normal;">FinalCheck具有</span><span style="font-weight: normal;">BoundsChecker提供的所有检错功能。</span><span style="font-weight: normal;">FinalCheck 是ActiveCheck的超集，它除了能够检测出ActiveCheck能够检测出的错误，还能发现很多 ActiveCheck 不能检测到的错误，包括：</span><span style="font-weight: normal;">指针操作错误、内存操作溢出、使用未初始化的内存等等，并且，对于</span><span style="font-weight: normal;">ActiveCheck能检测出的错误，FinalCheck能够给出关于错误更详细的信息。所以，我们可以把FinalCheck认为是ActiveCheck的功能增强版。我们付出的代价是：程序的运行速度会变慢，有时甚至会变的很慢。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">要想在FinalCheck 模式下测试程序，不能使用VC++集成开发环境提供的编译连接器来构造程序，而必须要使用BoundsChecker提供的编译连接器来编译连接程序。当 BoundsChecker的编译连接器编译连接程序时，会向程序中插装一些错误检测代码，这也就是FinalCheck能够比ActiveCheck找到更多错误的原因。</span></span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt;"><span style="font-size: 10.5pt;"><span style="font-size: 16px;">下面就</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">介绍一下如何在FinalCheck模式下对程序进行测试：</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">1在VC++集成开发环境中打开你所要测试的项目。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">2由于要使用BoundsChecker的编译连接器重新编译连接程序，所以我们为BoundsChecker独自构造一个文件夹。在VC++集成开发环境中，具体操作方法是：</span></span></p>
<p style="text-indent: 31.5pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">A)点击[ Build/Configurations...]菜单命令。</span></span></p>
<p><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">B)在弹出的对话框中点击 Add 按钮。在Configuration 编辑框中添入你为BoundsChecker创建的文件夹的名称，这个名称是任意的，比如我们取名为BoundChecker。</span></span></p>
<p><span style="font-size: 16px;"><span style="font-weight: normal;">C)在 Copy settings from组合框中选中</span> <tt><span style="font-weight: normal;">XXX&mdash;Win32 Debug项</span></tt><span style="font-weight: normal;">，然后点击OK按钮，接着点击Close按钮。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">现在，我们已经为FinalCheck构造好了一个文件夹。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">3 点击[Build/Set Active Configuration&hellip;] 菜单命令，选中你刚才为BoundsChecker建的文件夹，然后点击OK按钮。这样BoundsChecker编译连接程序时生成的中间文件、可执行程序，都会被放到该文件夹下。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-weight: normal; font-size: 10.5pt;"><span style="font-size: 16px;">4 选择[BoundsChecker/Rebuild All with BoundsChecker] 菜单命令，对程序重新进行编译连接，也就是在这时，BoundsChecker向被测程序的代码中加入了错误检测码。编译连接完成后， BoundsChecker会在你为BoundsChecker构造的文件夹中生成可执行文件。</span></span></p>
<p style="text-indent: 21pt;"><span style="font-size: 16px;"><span style="font-weight: normal;">在FinalCheck模式下对程序进行检测的准备工作都已经做好，这时可以启动程序开始测试了，</span></span></p>
<p style="text-indent: 21pt;"><span style="font-size: 16px;"><span style="font-weight: normal;">操作步骤与在</span><span style="font-weight: normal;">ActiveChecker模式下没什么区别。具体</span><span style="font-weight: normal;">步骤如下：</span></span></p>
<ol type="1" style="margin-top: 0cm;">
<li><span style="font-size: 16px;"><span style="font-weight: normal;">确保VC++集成开发环境中[BoundsChecker/ Integrated Debugging]菜单项和[BoundsChecker/Report Errors and Events]菜单项处于选中状态。</span> </span></li>
<li><span style="font-size: 16px;"><span style="font-weight: normal;">点击</span><span style="font-weight: normal;">[ Build\Start Debug]菜单，选中&ldquo;Go&rdquo; 菜单项。程序开始在Debug状态下运行。</span></span> </li>
<li><span style="font-size: 16px;"><span style="font-weight: normal;">按照你制定好的测试用例，对程序进行操作。</span><span style="font-weight: normal;">&nbsp;&nbsp;</span></span> </li>
<li><span style="font-size: 16px;"><span style="font-weight: normal;">当</span><span style="font-weight: normal;">BoundsChecker检测到了错误时，会弹出窗口向你汇报，你可以当时就进行处理，也可以等到你的操作全部完成，退出程序之后再对列出的这些错误进行分析。这完全取决于你是否选中了</span><span style="font-weight: normal;">[BoundsChecker/Report Errors Immediately] 菜单项。</span>&nbsp;&nbsp;</span> </li>
<li><span style="font-size: 16px;"><span style="font-weight: normal;">退出程序后，</span><span style="font-weight: normal;">BoundsChecker</span><span style="font-weight: normal;">会给出错误检测结果列表。该错误列表与ActiveChecker给出的错误列表的查看方法完全一样。只不过这个列表中所报告的信息会更多、更详细一些。</span> &nbsp;&nbsp;</span> </li>
</ol>
<p style="text-indent: 21pt;"><span style="font-size: 16px;"><span style="font-weight: normal;">好了，</span><span style="font-weight: normal;">BoundsChecker在</span><span style="font-weight: normal;">FinalCheck模式下的使用也介绍完了。</span><span style="font-weight: normal;">ActiveChecker、</span><span style="font-weight: normal;">FinalCheck这两种模式，比较而言各有长短。</span><span style="font-weight: normal;">ActiveChecker使用方便，只需在Debug状态下直接运行程序即可，并且程序的运行速度较快，但检测的错误种类有限；</span><span style="font-weight: normal;">FinalCheck模式下，需要使用</span><span style="font-weight: normal;">BoundsChecker的编译连接器重新编译连接生成可执行程序，并且程序的运行速度比较慢，但检测的错误种类、提供的错误相关信息要多于ActiveChecker。所以，何时使用何种模式，应根据当时的具体情况而定</span></span></p>
</div>
</div>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/249401#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 06 Oct 2008 15:09:31 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/249401</link>
        <guid>http://meizhini.javaeye.com/blog/249401</guid>
      </item>
          <item>
        <title>导入django的models出错.</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/234169" style="color:red;">http://meizhini.javaeye.com/blog/234169</a>&nbsp;
          发表时间: 2008年08月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>区别以下2种命令的进入,就知道2者区别了.也就知道为什么错了.</p>
<p>------------------------------------------------------------------------------------------------------------------------------</p>
<p>[ms]root python2.4<br />Python 2.4.4 (#2, Apr 15 2008, 23:43:20) <br />[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2<br />Type "help", "copyright", "credits" or "license" for more information.<br />&gt;&gt;&gt; from conf.models import *<br />Traceback (most recent call last):<br />&nbsp; File "&lt;stdin&gt;", line 1, in ?<br />&nbsp; File "/e/work/hainan_ms/ms/../ms/conf/models.py", line 2, in ?<br />&nbsp;&nbsp;&nbsp; from django.db import models<br />&nbsp; File "/usr/lib/python2.4/site-packages/django/db/__init__.py", line 7, in ?<br />&nbsp;&nbsp;&nbsp; if not settings.DATABASE_ENGINE:<br />&nbsp; File "/usr/lib/python2.4/site-packages/django/conf/__init__.py", line 28, in __getattr__<br />&nbsp;&nbsp;&nbsp; self._import_settings()<br />&nbsp; File "/usr/lib/python2.4/site-packages/django/conf/__init__.py", line 53, in _import_settings<br />&nbsp;&nbsp;&nbsp; raise EnvironmentError, "Environment variable %s is undefined." % ENVIRONMENT_VARIABLE<br />EnvironmentError: Environment variable DJANGO_SETTINGS_MODULE is undefined.</p>
<p>------------------------------------------------------------------------------------------------------------------------------</p>
<p>[ms]root python2.4 manage.py shell <br />Python 2.4.4 (#2, Apr 15 2008, 23:43:20) <br />[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2<br />Type "help", "copyright", "credits" or "license" for more information.<br />(InteractiveConsole)<br />&gt;&gt;&gt; from conf.models import *<br />&gt;&gt;&gt; </p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/234169#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 28 Aug 2008 21:30:50 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/234169</link>
        <guid>http://meizhini.javaeye.com/blog/234169</guid>
      </item>
          <item>
        <title>安装setuptools</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/227535" style="color:red;">http://meizhini.javaeye.com/blog/227535</a>&nbsp;
          发表时间: 2008年08月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>setuptools</p>
<p>有时候安装python的一些软件的时候会提示你setuptools之类的东西,这是这这个东西你没有安装好.所以你没有办法安装你要装大软件.</p>
<p>这里不再说什么原理性的东西,仅仅是说说如何安装setuptools.</p>
<p><br />&nbsp;</p>
<p>1.&nbsp;&nbsp; <span style="font-family: Courier New;">wget -q <a href="http://peak.telecommunity.com/dist/ez_setup.py">http://peak.telecommunity.com/dist/ez_setup.py</a></span></p>
<p><span style="font-family: Courier New;">2.python ez_setup.py&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 这一步必然失败,是为了第三步取得url准备的.)</span></p>
<p><span style="font-family: Courier New;">运行这行的时候,linux会停留在Downling ~~~~~这类似的上面.</span></p>
<p><span style="font-family: Courier New;">这是因为你的这个目录下中没有</span><span style="font-family: Verdana;">setuptools-0.6c8-py2.4.egg东西.</span></p>
<p>3.&nbsp;&nbsp;&nbsp; wget http://pypi.python.org/packages/2.4/s/setuptools/setuptools-0.6c8-py2.4.egg</p>
<p>注意:第三步的url是根据第二步得到的url.</p>
<p>&nbsp;</p>
<p>这时候你再运行第二步.之后再运行安装你前面不能够安装的软件.应该就解决了setuptools方面的问题了.</p>
<p>&nbsp;</p>
<p>关键东西:是要准备好2个东西:ez_setup.py和setuptools-0.6c8-py2.4.egg.</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/227535#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 13 Aug 2008 14:01:42 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/227535</link>
        <guid>http://meizhini.javaeye.com/blog/227535</guid>
      </item>
          <item>
        <title>python的变量与函数重名导致的问题</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/218515" style="color:red;">http://meizhini.javaeye.com/blog/218515</a>&nbsp;
          发表时间: 2008年07月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>python有一个奇怪的名字空间,就是函数与变量是不能够有相同的名字的.而且会发现没有调用查询出来的数据,却报告 'TypeError: 'ResultProxy' object is not callable'异常.</p>
<p>例如:</p>
<p>--------------------------------------------------------</p>
<p>mysql://root:root@127.0.0.1:33066/nxrdb<br />here b<br />Traceback (most recent call last):<br />&nbsp; File "dns_util.py", line 37, in ?<br />&nbsp;&nbsp;&nbsp; dns_list( dns_list )<br />TypeError: 'ResultProxy' object is not callable</p>
<p>---------code-------------------------------------------------------<br />from dns_config import Rt_dns, Dns_stat<br />import traceback<br /><br />def dns_list( t_cls_list ):<br />&nbsp;&nbsp;&nbsp; pass<br />#<br />if ( __name__ == "__main__" ):<br />&nbsp;&nbsp;&nbsp; #dns_list( [] );<br />&nbsp;&nbsp;&nbsp; from dbconn import DbBase<br />&nbsp;&nbsp;&nbsp; db_2 = DbBase()<br />&nbsp;&nbsp;&nbsp; try:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dns_list = db_2.query( "select * from conf_correct_dns_records limit 10" )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print "here b"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dns_list( dns_l )<br />&nbsp;&nbsp;&nbsp; except:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; traceback.print_exc( 5 )<br />&nbsp;&nbsp;&nbsp; dns_list.close()<br />&nbsp;&nbsp;&nbsp; #print len( d )</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/218515#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 23 Jul 2008 11:59:55 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/218515</link>
        <guid>http://meizhini.javaeye.com/blog/218515</guid>
      </item>
          <item>
        <title>Ignoring query to other database</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/218450" style="color:red;">http://meizhini.javaeye.com/blog/218450</a>&nbsp;
          发表时间: 2008年07月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>区别一下:</p>
<p>mysql -root -proot </p>
<p>#</p>
<p>mysql -uroot -proot</p>
<p>发现少了一个"u".导致了"Ignoring query to other database".</p>
<p>首先检查登录是否正确.再看其他的问题吧!</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/218450#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 23 Jul 2008 08:20:40 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/218450</link>
        <guid>http://meizhini.javaeye.com/blog/218450</guid>
      </item>
          <item>
        <title>D语言安装,以及编译</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/216498" style="color:red;">http://meizhini.javaeye.com/blog/216498</a>&nbsp;
          发表时间: 2008年07月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2>如果做完以下步骤,还是不能够运行,请看&quot;-------------&quot;以下部分,那是我个人安装经历.<br />
</h2>
<h2>linux下 D 语言编译器安装</h2>
<div class="t_msgfont" id="postmessage_24"><span class="t_tag" onclick="tagshow(event)">linu</span>
x&quot; onclick=&quot;tagshow(event)&quot; class=&quot;t_tag&quot;&gt;<span class="t_tag" onclick="tagshow(event)">linu</span>
x<span class="t_tag" onclick="tagshow(event)">下</span>
 D <span class="t_tag" onclick="tagshow(event)">语言编译</span>
器安装<br />
DMD<span class="t_tag" onclick="tagshow(event)">在</span>
Ubuntu下的安装配置<br />
<br />
D语言是下一个主流静态语言霸主的强有力候选人。DMD是D语言的一个编译器。<br />
到下面的地址下载<span class="t_tag" onclick="tagshow(event)">dmd</span>
，后解压。（其中<span class="t_tag" onclick="tagshow(event)">dmd</span>
/src/<span class="t_tag" onclick="tagshow(event)">dmd</span>
是<span class="t_tag" onclick="tagshow(event)">dmd</span>
的源码，<span class="t_tag" onclick="tagshow(event)">dmd</span>
/sample/d是d语言的几个简单示例。）<br />
<a href="http://www.digitalmars.com/d/dcompiler.html" target="_blank">http://www.digitalmars.com/d/dcompiler.html</a>
<br />
<br />
<span style="color: #ff0000;">&nbsp; &nbsp;1. 安装配置文件，复制dmd/bin/dmd.conf到 /<span class="t_tag" onclick="tagshow(event)">usr</span>
/<span class="t_tag" onclick="tagshow(event)">local</span>
/bin下。<br />
&nbsp; &nbsp;2. 为dmd/bin下的这几个文件添加执行权限，dmd,dumpobj,obj2asm,rdmd。<br />
&nbsp; &nbsp;3. 安装编译器，复制上面的几个文件到 /usr/local/bin。<br />
&nbsp; &nbsp;4. 安装lib，复制dmd/lib/libphobos2.a 到 /usr/local/lib。<br />
&nbsp; &nbsp;5. 安装源码，复制dmd/src/phobos到/usr/local/src。<br />
&nbsp; &nbsp;6. 安装<span class="t_tag" onclick="tagshow(event)">man</span>
，复制dmd/<span class="t_tag" onclick="tagshow(event)">man</span>
/<span class="t_tag" id="tag_0.8938828800485681" onclick="tagshow(event)">man</span>
1下的所有文件到/usr/local/<span class="t_tag" onclick="tagshow(event)">man</span>
/<span class="t_tag" onclick="tagshow(event)">man</span>
1下。</span>
<br />
<br />
这样就OK了。</div>
<div class="t_msgfont">以上是网络上的安装步骤.</div>
<div class="t_msgfont">做完之后,需要验证下,是否已经安装好了.就需要做下面的一步.<br />
</div>
<div class="t_msgfont">-------------------------------hello.d--------------------------------<br />
</div>
<div class="t_msgfont">import std.stdio;<br />
void main ( char [][] args )<br />
{<br />
&nbsp;&nbsp;&nbsp; int a = 1;<br />
&nbsp;&nbsp;&nbsp; a += 1;<br />
&nbsp;&nbsp;&nbsp; typeof( a ) k ;<br />
&nbsp;&nbsp;&nbsp; k = 1000;<br />
&nbsp;&nbsp;&nbsp; writefln(&quot;hello world&quot;,k);<br />
}<br />
#reboot</div>
<div class="t_msgfont">重启机器.</div>
<div class="t_msgfont">再来编译.d文件,就ok了.</div>
<div class="t_msgfont">#dmd hello.d</div>
<div class="t_msgfont">#./hello</div>
<div class="t_msgfont">hello world1000<br />
</div>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/216498#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 19 Jul 2008 14:13:59 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/216498</link>
        <guid>http://meizhini.javaeye.com/blog/216498</guid>
      </item>
          <item>
        <title>设计变化了</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/215588" style="color:red;">http://meizhini.javaeye.com/blog/215588</a>&nbsp;
          发表时间: 2008年07月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; 好久没有来写这一栏了.</p>
<p>&nbsp;&nbsp;&nbsp; 最近页是特别忙.听说奥运要封网----就是不许让他人在大型网络服务器的机房里面添加设备,和重大的修改.正好,我们的公司也是与电信打交道的,所以我们希望在这之前把上一个项目.所以我们天天加班.</p>
<p>&nbsp;&nbsp;&nbsp; 不过,现在计划出现了变动,我们的设备部门还没有准备好机器.项目只好推后了.</p>
<p>&nbsp;&nbsp;&nbsp; 在这段时间我与一个同事共同维护一个文件XXX.bat.我从数据库中每过1分钟读取一次数据库,把相应的东西写入到xxx文件.它则每过1~2分钟读取一次xxx文件.这是我之前规则.当时我就提出来,我是否在修改了xxx文件之后,马上通知你呢?他说没有必要,他每过1~2分钟就读取一次文件.</p>
<p>&nbsp;&nbsp;&nbsp; 我这边还要监听一个udp包,如是要重新flush这个文件,我立即读取数据,重写xxx文件.我这边使用的是udp监听和线程的方法,所以不会出现消耗内存的情况.</p>
<p>&nbsp;&nbsp;&nbsp; 他那边,设计为中转站,还有另一个同事写了一个模块,通知他和我的模块,数据库被修改了,我们就立即开始准备操作xxx文件.我写文件可能会出现比较慢的情况,因为数据太多.所以他那本就设计为------不断读这个文件,直到读取到---用一个while循环实现,具体条件没有查看他的.</p>
<p>&nbsp;&nbsp;&nbsp; 后来他觉得我们还是用udp通讯吧.就是我这边如果frelush数据到xxx文件中,那么就发udp包通知他.</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 我们就开始了一段bug历程.</p>
<p>&nbsp;&nbsp;&nbsp; 当我把我的模块修改好,之后,就是去配置测试机器.环境搭好,我写一个sh文件作为启动程序,我们开始都能够正常运行.他的突然崩溃了.</p>
<p>&nbsp;&nbsp;&nbsp; 为什么?我不知道.你知道是什么原因吗?如果你看到这里能猜到他的程序出现了什么原因,说明你要么就是一个阅读高手,要么就是编程高手.</p>
<p>&nbsp;&nbsp;&nbsp; 他修改了一个下午程序,最后告诉我,他的程序是这样工作的:收到我的udp包还是用while循环方式去读取文件.他说问题就出在不断读取的上面导致内存(具体是内存还是死循环不是很记得了)问题.</p>
<p>&nbsp;&nbsp;&nbsp; 读取方式本身就不对,应该只读一次,就对了.</p>
<p>&nbsp;&nbsp;&nbsp; 问题说到这里,也就能够解决了,我想说的是,小心设计中间变化的问题.</p>
<p>&nbsp;&nbsp;&nbsp; 前面是好的,通信变化了,就需要考虑了.其他的也是一样类似的.</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/215588#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 16 Jul 2008 23:07:43 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/215588</link>
        <guid>http://meizhini.javaeye.com/blog/215588</guid>
      </item>
          <item>
        <title>python在c中被调用</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/209548" style="color:red;">http://meizhini.javaeye.com/blog/209548</a>&nbsp;
          发表时间: 2008年06月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>cc -lpython2.4 py_2_c.c</p>
<p>cc -lpython2.4 py_2_c_str.c -o a</p>
<p>cc -lpython2.4 adv_issue.c -o adv_issue</p>
<p><br />
#include &lt;python2.4/Python.h&gt;<br />
int main( int argc , char ** argv )<br />
{<br />
&nbsp;&nbsp;&nbsp; Py_Initialize();<br />
&nbsp;&nbsp;&nbsp; PyRun_SimpleString( &quot;print 'qqqqqqqqqqqq'&quot; );<br />
&nbsp;&nbsp;&nbsp; Py_Finalize();<br />
&nbsp;&nbsp;&nbsp; return 0;<br />
}</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/209548#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 29 Jun 2008 22:50:53 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/209548</link>
        <guid>http://meizhini.javaeye.com/blog/209548</guid>
      </item>
          <item>
        <title>c扩展python实战</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/209155" style="color:red;">http://meizhini.javaeye.com/blog/209155</a>&nbsp;
          发表时间: 2008年06月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; 以下内容不是适合python高手看,仅仅是为第一次看&lt;<span style="background-color: #00ff00;">c扩展python</span>
&gt;引路.希望中国的孩子不要迷路.</p>
<p>&nbsp;&nbsp;&nbsp; 看了很多人的&lt;c扩展python&gt;,写的非常的精彩.可是却少了实际操作.这些人,都把我们当成了c高手来对待.在编译的时候仅仅是一笔带过.说什么把模块<span style="background-color: #ff0000;">编译连接</span>
之后就可以使用.他却不知道我是那么的菜.</p>
<p>&nbsp;&nbsp;&nbsp; 而且还给出了使用例子:</p>
<p style="background-color: #ffff99;">&nbsp;&nbsp;&nbsp; &gt;&gt;import foo</p>
<p style="background-color: #ffff99;">&nbsp;&nbsp;&nbsp; &gt;&gt;foo.bar( '11111' )</p>
<p style="background-color: #ffff99;">&nbsp;&nbsp;&nbsp; 5</p>
<p>&nbsp;&nbsp;&nbsp; 如果觉得自己已经了解了如何编译成python可以使用的东西,那么就不浪费你的宝贵的时间看下去了,而是给我投以鄙视的目光:这么简单的问题,还那来说.</p>
<p>&nbsp;&nbsp;&nbsp; 下面给出例子:在我的linux板块下有&lt;Linux动态链接库编程入门&gt;.</p>
<p>&nbsp;</p>
<p>&nbsp; /*foomain.c*/  </p>
<p>#include &lt;python2.4/Python.h&gt;<br />
/* Define the method table. */<br />
static PyObject *foo_bar(PyObject *self, PyObject *args);<br />
static PyMethodDef FooMethods[] = {<br />
&nbsp;&nbsp; {&quot;bar&quot;,&nbsp; foo_bar, METH_VARARGS},<br />
&nbsp;&nbsp; {NULL, NULL}<br />
};<br />
/* Here's the initialization function.&nbsp; We don't need to do anything<br />
&nbsp;*&nbsp;&nbsp;&nbsp; for our own needs, but Python needs that method table. */<br />
void initfoo()<br />
{<br />
&nbsp;&nbsp; (void) Py_InitModule(&quot;foo&quot;, FooMethods);<br />
}<br />
/* Finally, let's do something ... involved ... as an example function. */<br />
static PyObject *foo_bar(PyObject *self, PyObject *args)<br />
{<br />
&nbsp;&nbsp; char *string;<br />
&nbsp;&nbsp; int&nbsp;&nbsp; len;<br />
&nbsp;&nbsp; if (!PyArg_ParseTuple(args, &quot;s&quot;, &amp;string))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br />
&nbsp;&nbsp; len = strlen(string);<br />
&nbsp;&nbsp; return Py_BuildValue(&quot;i&quot;, len);<br />
}</p>
<p>&nbsp;</p>
<p>在linux下的运行: gcc -fPIC -shared -o foo.so foomain.c 这一段就ok了.</p>
<p>当前目录下会出现&quot;foo.so&quot;文件.这就是我们一直不明白那些作者说的东西.</p>
<p>现在在到前面python运行环境下去调用就好了(淡黄区域标示处),不会到了这一步好要我给重复给出示例吧?</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/209155#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 29 Jun 2008 09:31:04 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/209155</link>
        <guid>http://meizhini.javaeye.com/blog/209155</guid>
      </item>
          <item>
        <title>Linux动态链接库编程入门</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/209154" style="color:red;">http://meizhini.javaeye.com/blog/209154</a>&nbsp;
          发表时间: 2008年06月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="font-size: medium;"><strong>Linux动态链接库编程入门</strong>
</span>
<br />
<strong></strong>
        
         
          
               
                &nbsp; </p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">动态链接库是一种通用的软件组件技术，是多种操作系统中提供基本服务的方式。比如</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Win32</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">内核就是</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">3</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">个</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">DLL</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">文件构成。这种技术在</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Linux</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">操作系统下也有对应的实现，就是</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Linux</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">标准对象</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Standard Ojbect</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">，对应的文件扩展名为</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">.so</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">。</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">下面通过一个简单的例子开始介绍</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Linux</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">标准对象。</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">我们的标准对象文件含有一个函数，不需要声明</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">export</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">导出符号，只需要编译器设置即可。如下：</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">#include &lt;stdio.h&gt;</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">#include &lt;stdlib.h&gt;</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">void show() {</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
printf(&quot;Standard Object by gashero\n&quot;);</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">}</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">保存为</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">myso.c</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">文件，按照如下编译：</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">$ gcc -fPIC -shared -o libmyso.so myso.c</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">执行生成一个</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">libmyso.so</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">文件，按照</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Linux</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">标准对象的命名惯例，应该在库名称之前加上</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">&quot;lib&quot;</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">前缀，尽管不是必须的。编译开关</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">-fPIC</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">代表函数符号可以重定向，</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">-shared</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">代表编译结果是一个标准对象。</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">不同于</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Win32DLL</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">，</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Linux</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">标准对象中的所有函数都是直接导出的，都可以被调用程序所访问。下面我们编写调用程序：</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">#include &lt;stdio.h&gt;</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">int main() {</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
printf(&quot;Invoke my so\n&quot;);</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
show();</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
return 0;</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">}</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">保存为</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">invoke.c</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">，按照如下</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">gcc</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">开关编译：</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">$ gcc -o test invoke.c ./libmyso.so</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">编译生成</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">test</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">可执行文件。如上编译条件的最后一条需要是所调用的标准对象文件名，注意必须含有路径。如果只是使用</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">libmyso.so</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">，则必须确保这个文件在可访问的</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">PATH</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">下面。本例所使用的文件名</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">&quot;./libmyso.so&quot;</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">是当前路径下的，使用了相对路径。</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp; </span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">如下测试结果：</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;"></span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">$ ./test</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Invoke my so</span>
</p>
<p class="MsoNormal" align="left" style="line-height: 150%; text-align: left;"><span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Standard Object by gashero</span>
</p>
<p><span lang="EN-US" style="font-size: 12pt; line-height: 150%;"><span>&nbsp;</span>
</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">希望上文的例子可以对大家有所帮助，这也是我的毕业设计题目，待我完成之后会有一份更加完整的文档介绍</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Win32DLL</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">和</span>
<span lang="EN-US" style="font-size: 12pt; line-height: 150%;">Linux.so</span>
<span style="font-size: 12pt; line-height: 150%; font-family: 宋体;">的。</span>
</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://meizhini.javaeye.com/blog/209154#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 29 Jun 2008 09:22:32 +0800</pubDate>
        <link>http://meizhini.javaeye.com/blog/209154</link>
        <guid>http://meizhini.javaeye.com/blog/209154</guid>
      </item>
          <item>
        <title>用 C 扩展 Python 和 Zope</title>
        <author>meizhini</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://meizhini.javaeye.com">meizhini</a>&nbsp;
                    链接：<a href="http://meizhini.javaeye.com/blog/208999" style="color:red;">http://meizhini.javaeye.com/blog/208999</a>&nbsp;
          发表时间: 2008年06月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>来源于:http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html</p>
<p>&nbsp;</p>
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr valign="top">
<td width="100%">
<h1>用 C 扩展 Python 和 Zope</h1>
<p id="subtitle"><em>两全其美</em>
</p>
<img class="display-img" src="http://www.ibm.com/i/c.gif" height="6" alt="" width="1" />
</td>
<td class="no-print" width="192"><img src="http://www.ibm.com/developerworks/i/dw.gif" height="18" alt="developerWorks" width="192" />
</td>
</tr>
</tbody>
</table>
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr valign="top">
<td width="10"><img src="http://www.ibm.com/i/c.gif" height="1" alt="" width="10" />
</td>
<td width="100%">
<table class="no-print" cellspacing="0" border="0" align="right" width="160" cellpadding="0">
<tbody>
<tr>
<td width="10"><img src="http://www.ibm.com/i/c.gif" height="1" alt="" width="10" />
</td>
<td>
<table cellspacing="0" border="0" width="150" cellpadding="0">
<tbody>
<tr>
<td class="v14-header-1-small">文档选项</td>
</tr>
</tbody>
</table>
<table class="v14-gray-table-border" cellspacing="0" border="0" cellpadding="0">
<tbody>
<tr>
<td class="no-padding" width="150"><img src="http://www.ibm.com/i/c.gif" height="1" alt="" width="8" />
<input name="body" type="hidden" value="一旦明白怎样用 C 扩展 Phthon，您就会知道这很容易，把 Python 扩展封装到 Zope 中也同样容易。难点是如何从各式各样的文档集中找到那些您需要的重要信息，而 Michael 已在本文帮您收集了这些信息。" />
<input name="subject" type="hidden" value="用 C 扩展 Python 和 Zope" />
<input name="lang" type="hidden" value="cn" />
<noscript>&lt;tr
valign=&quot;top&quot;&gt;&lt;td width=&quot;8&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;8&quot;
src=&quot;//www.ibm.com/i/c.gif&quot;/&gt;&lt;/td&gt;&lt;td width=&quot;16&quot;&gt;&lt;img alt=&quot;&quot; width=&quot;16&quot;
height=&quot;16&quot; src=&quot;//www.ibm.com/i/c.gif&quot;/&gt;&lt;/td&gt;&lt;td class=&quot;small&quot;
width=&quot;122&quot;&gt;&lt;p&gt;&lt;span class=&quot;ast&quot;&gt;未显示需要 JavaScript
的文档选项&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;</noscript>
<table cellspacing="0" border="0" width="143" cellpadding="0">
<form action="https://www.ibm.com/developerworks/secure/email-it.jsp"></form>
<script type="text/javascript">
&lt;!--
document.write('&lt;tr valign=&quot;top&quot;&gt;&lt;td width=&quot;8&quot;&gt;&lt;img src=&quot;//www.ibm.com/i/c.gif&quot; width=&quot;8&quot; height=&quot;1&quot; alt=&quot;&quot;/&gt;&lt;/td&gt;&lt;td width=&quot;16&quot;&gt;&lt;img src=&quot;//www.ibm.com/i/v14/icons/em.gif&quot; height=&quot;16&quot; width=&quot;16&quot; vspace=&quot;3&quot; alt=&quot;将此页作为电子邮件发送&quot; /&gt;&lt;/td&gt;&lt;td width=&quot;122&quot;&gt;&lt;p&gt;&lt;a class=&quot;smallplainlink&quot; href=&quot;javascript:document.email.submit();&quot;&gt;&lt;b&gt;将此页作为电子邮件发送&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;');
//--&gt;
</script>
<tbody>
<tr valign="top">
<td width="8"><img src="http://www.ibm.com/i/c.gif" height="1" alt="" width="8" />
</td>
<td width="16"><img src="http://www.ibm.com/i/v14/icons/em.gif" vspace="3" height="16" alt="将此页作为电子邮件发送" width="16" />
</td>
<td width="122">
<p><a href="javascript:document.email.submit();" class="smallplainlink"><strong>将此页作为电子邮件发送</strong>
</a>
</p>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!--  this content will be automatically generated across all content areas --><!-- END RESERVED FOR FUTURE USE INCLUDE FILES--><br />
</td>
</tr>
</tbody>
</table>
<p>级别： 初级</p>
<p><a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#author">Michael Roberts</a>
 (<a href="mailto:michael@vivtek.com?subject=%E7%94%A8%20C%20%E6%89%A9%E5%B1%95%20Python%20%E5%92%8C%20Zope&amp;cc=michael@vivtek.com">michael@vivtek.com</a>
), 业主, Vivtek</p>
<p>2001 年  8 月  01 日</p>
<blockquote>一旦明白怎样用 C 扩展 Phthon，您就会知道这很容易，把 Python 扩展封装到 Zope 中也同样容易。难点是如何从各式各样的文档集中找到那些您需要的重要信息，而 Michael 已在本文帮您收集了这些信息。</blockquote>
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!--  include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
<!-- END RESERVED FOR FUTURE USE INCLUDE FILES-->
<p>有几个原因使您可能想用 C 扩展
Zope。最可能的是您有一个已能帮您做些事的现成的 C
库，但是您对把它转换成 Python 却不感兴趣。此外，由于 Python
是解释性语言，所以任何被大量调用的 Python
代码都将降低您的速度。因此，即使您已经用 Python
写了一些扩展，您仍然要考虑把其中最常被调用的部分改用 C
来写。不论哪种方式，扩展 Zope 都是从扩展 Python 开始。此外，扩展
Python 会给您带来其它的好处，因为您的代码将可以从任何 Python
脚本访问，而不只是从 Zope。这里唯一要提醒的是在写本文的时候，Python
的当前版本是 2.1，但是 Zope 仍然只能和 Python 1.5.2 一起运行。对 C
扩展来说，两个版本并没有什么变化，但如果您有兴趣对您的库进行 Python
包装，又想让它们都能在 Zope 下工作，您就得注意不要使用任何比 1.5.2
更新的东西。</p>
<table cellspacing="0" border="0" align="right" width="40%" cellpadding="0">
<tbody>
<tr>
<td width="10"><img src="http://www.ibm.com/i/c.gif" height="1" alt="" width="10" />
</td>
<td>
<table cellspacing="0" border="1" width="100%" cellpadding="5">
<tbody>
<tr>
<td bgcolor="#eeeeee">
        <a name="N10046"><strong>Zope 是什么？</strong>
</a>
<br />
<p>Zope 代表&ldquo;Z Object Publishing Environment（Z
对象发布环境）&rdquo;，它是用 Python
实现的应用程序服务器。&ldquo;太棒了，&rdquo;您说，&ldquo;但应用程序服务器的确切含义是什么呢？&rdquo;应用程序服务器就是一个长期运行的进程，它为&ldquo;活动的内容&rdquo;提供服务。Web
服务器在运行期间调用应用程序服务器来构建页面。</p>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="1"><span class="atitle">扩展 Python：有趣又有益</span>
</a>
</p>
<p>
想扩展 Zope，您首先要扩展 Python。虽然扩展 Python
不像&ldquo;脑外科手术&rdquo;那样复杂，但也不像&ldquo;在公园中散步&rdquo;那样悠闲。有两个基本组件用于
Python 扩展。第一个显然是 C 代码。我将马上探讨它。
另一个部分是
        <em>安装文件</em>
。安装文件通过提供模块名称、模块的 C
代码的位置和您可能需要的所有编译器标志来描述模块。该文件被预处理，以创建
makefile（在 UNIX 上）或 MSVC++ 工程文件（MSVC++ project file，在
Windows 上）。先说一下 ― Windows 上的 Python 事实上是用 Microsoft
编译器编译的。Python.org 的人也推荐用 MSVC++
编译扩展。显然，您应该能够成功说服 GNU
的编译者们，但我本人还没试过。
      </p>
<p>无论如何，还是让我们来定义一个叫做&lsquo;foo&rsquo;的模块吧。&lsquo;foo&rsquo;模块会有一个叫做&lsquo;bar&rsquo;的函数。当我们要使用时，我们可以用 
        <code>import foo;</code>
 来把这个函数导入到 Python 脚本中，就跟导入任何模块一样。安装文件非常简单：
      </p>
<br />
<a name="code"><strong>清单 1.
一个典型的安装文件</strong>
</a>
<br />
 
      
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode"># You can include comment lines.  The *shared* directive indicates
# that the following module(s) are to be compiled and linked for
# dynamic loading as opposed to static: .so on Unix, .dll on Windows.
*shared*
# Then you can use the variables later using the $(variable) syntax
# that 'make' uses.  This next line defines our module and tells
# Python where its source code is.
foo foomain.c
</pre>
</td>
</tr>
</tbody>
</table>
<br />
 
      <br />
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" />
<br />
<img src="http://www.ibm.com/i/c.gif" border="0" height="6" alt="" width="8" />
</td>
</tr>
</tbody>
</table>
<table class="no-print" cellspacing="0" border="0" align="right" cellpadding="0">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" height="4" alt="" width="100%" />
<br />
<table cellspacing="0" border="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" alt="" width="16" />
<br />
</td>
<td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#main" class="fbox"><strong>回页首</strong>
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<br />
<p><a name="2"><span class="atitle">编写代码</span>
</a>
</p>
<p>
那么我们实际上该怎样写 Python
知道如何使用的代码呢，您问？ 
        <code>foomain.c</code>
 （当然，您可以随意命名它）文件包含三项内容：一个方法表，一个初始化函数和其余的代码。方法表简单地将函数名与函数联系起来，并告知
Python
各个函数所使用的参数传递机制（您可以选择使用一般的位置参数列表或位置参数和关键词参数的混合列表）。Python
在模块装入时调用初始化函数。初始化函数将完成模块所要求的所有初始化操作，但更重要的是，它还把一个指向方法表的指针传回给
Python。
      </p>
<p>那我们就来看看我们的小型 foo 模块的 C 代码。</p>
<br />
<a name="code"><strong>清单 2. 一个典型的 Python
扩展模块</strong>
</a>
<br />
 
      
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">#include &lt;Python.h&gt;
/* Define the method table. */
static PyObject *foo_bar(PyObject *self, PyObject *args);
static PyMethodDef FooMethods[] = {
   {&quot;bar&quot;,  foo_bar, METH_VARARGS},
   {NULL, NULL}
};
/* Here's the initialization function.  We don't need to do anything
   for our own needs, but Python needs that method table. */
void initfoo()
{
   (void) Py_InitModule(&quot;foo&quot;, FooMethods);
}
/* Finally, let's do something ... involved ... as an example function. */
static PyObject *foo_bar(PyObject *self, PyObject *args)
{
   char *string;
   int   len;
   if (!PyArg_ParseTuple(args, &quot;s&quot;, &amp;string))
       return NULL;
   len = strlen(string);
   return Py_BuildValue(&quot;i&quot;, len);
}</pre>
</td>
</tr>
</tbody>
</table>
<br />
<p><a name="N10087"><span class="smalltitle">深入研究</span>
</a>
</p>
<p>
我们来看会儿这些代码。首先，请注意您必须包含 
        <code>Python.h</code>
 。除非您已在包含路径（include
path）中设置了该文件的路径，否则您可能需要在安装文件中包含 
        <code>-I</code>
 标志以指向该文件。
      </p>
<p>初始化函数必须命名为 
        <code>init</code>
 &lt;模块名&gt;，在我们的例子中是 
        <code>initfoo</code>
 。初始化函数的名称，毫无疑问，是 Python
在装入模块时所知道的关于模块的全部信息，这也是初始化函数的名称如此死板的原因。顺便说一下，初始化函数必须是文件中唯一未被声明为 
        <code>static</code>
 
的全局标识符。这对静态链接比对动态链接更重要，因为非 
        <code>static</code>
 
标识符将是全局可见的。对动态链接来说，这不是一个很大的问题，但如果您打算在编译期间链接所有东西，又没有把所有可以声明为 
        <code>static</code>
 的东西声明为 
        <code>static</code>
 ，那么您很可能就会碰到名称冲突的问题。
      </p>
<p>
现在我们来观察实际的代码，看看参数是怎样被处理的，返回值又是怎样被传递的。当然，一切都是
PyObject ― Python
堆上的对象。您从参数中得到的是一个对&ldquo;this&rdquo;对象的引用（this
用于对象方法，对类似 
        <code>bar()</code>
 
这样的无参数的老式函数来说是 NULL）和一个存储在 
        <code>args</code>
 
中的参数元组。您用 
        <code>PyArg_ParseTuple</code>
 
找回您的参数，然后用 
        <code>Py_BuildValue</code>
 
把结果传回去。这些函数（还有更多）都归档在 Python 文档的&ldquo;Python/C
API&rdquo;部分中。不幸的是，没有按名称排列的简单的函数清单，文档是按主题排列的。
      </p>
<p>另请注意，函数在出错的情况下返回 NULL。返回 NULL
表示出错了；如果想让 Python
做得更好，您应该抛出异常。我会指点您去查阅关于如何做这件事的文档。</p>
<br />
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" />
<br />
<img src="http://www.ibm.com/i/c.gif" border="0" height="6" alt="" width="8" />
</td>
</tr>
</tbody>
</table>
<table class="no-print" cellspacing="0" border="0" align="right" cellpadding="0">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" height="4" alt="" width="100%" />
<br />
<table cellspacing="0" border="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" alt="" width="16" />
<br />
</td>
<td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#main" class="fbox"><strong>回页首</strong>
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<br />
<p><a name="3"><span class="atitle">编译扩展</span>
</a>
</p>
<p>
现在剩下的全部问题是编译模块。您可以通过两种方式进行。第一种是按照文档中的指导，运行 
        <code>make -f Makefile.pre.in boot</code>
 ，这样将会使用您的 Setup
来编译一个 Makefile。然后您就用该 Makefile
编译您的工程。这种方式只适用于 UNIX。对 Windows
来说，存在一个叫&ldquo;compile.py&rdquo;的脚本（请参阅本文后面的
        <a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#resources">参考资料</a>
）。原始脚本很难找到；我从一个邮件列表中找到了一个来自
Robin Dunn（wxPython
的幕后工作者）的被大量改动了的副本。这个脚本能在 UNIX 和 Windows
上工作；在 Windows 上，它将从您的 Setup 开始编译 MSVC++
工程文件。
      </p>
<p>要进行编译，您必须使包含的文件和库都可用。Python 的标准 Zope
安装没有包含这些文件，因此您需要从 www.python.org（请参阅
        <a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#resources">参考资料</a>
）安装 Python 的常规安装。在 Windows
上，您还必须从源代码安装的 PC 目录中获取 config.h 文件；它是 UNIX
安装为您编译的 config.h 的手工版。因此，在 UNIX
上，您应该已经拥有它了。
      </p>
<p>
一旦这些都完成后，您就会得到一个以&ldquo;.pyd&rdquo;为扩展名的文件。把这个文件放到
Python 安装目录下的&ldquo;lib&rdquo;目录（在 Zope 下，Python
位于&ldquo;bin&rdquo;目录，因此您的扩展得结束于&ldquo;bin/lib&rdquo;目录，奇怪吧。）然后您就可以调用它了，就像调用任何源生的
Python 模块一样。</p>
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode"> &gt;&gt;&gt; import foo;
  &gt;&gt;&gt; foo.bar (&quot;This is a test&quot;);
  14
</pre>
</td>
</tr>
</tbody>
</table>
<br />
<p>做到这里时，我的第一个问题是问自己该如何用 C 定义从 Python
中可见的
        <em>类</em>
。事实上，我可能问了一个错误的问题。在我已研究的示例中，特定于
Python 的一切都只
        <em>用 Python</em>
来完成，也都只调用从您的扩展中导出的 C 函数。
      </p>
<br />
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" />
<br />
<img src="http://www.ibm.com/i/c.gif" border="0" height="6" alt="" width="8" />
</td>
</tr>
</tbody>
</table>
<table class="no-print" cellspacing="0" border="0" align="right" cellpadding="0">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" height="4" alt="" width="100%" />
<br />
<table cellspacing="0" border="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" alt="" width="16" />
<br />
</td>
<td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#main" class="fbox"><strong>回页首</strong>
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<br />
<p><a name="4"><span class="atitle">把它带到 Zope 中去</span>
</a>
</p>
<p>一旦完成了您的 Python 扩展，下一步就是使 Zope
能和它一起工作。您有几种方式可以选择，但在一定程度上，您希望您的扩展以什么方式与
Zope 一起工作将首先影响到您编译扩展的方式。从 Zope 内使用
Python（以及用 C 所做的扩展）代码的基本方式是：</p>
<ul>
<li>
如果函数很简单，您可以把它当作一个变量。这些被叫做&ldquo;外部方法&rdquo;。</li>
<li>更复杂的类，可以从 Zope 脚本中调用（这是 Zope 2.3
的一个新功能）。</li>
<li>您可以定义一个 Zope Product，然后可以用
ZClass（一组已做好的、Web
可访问的对象）扩展它，在脚本中使用它，根据它的自有权限发布它（它的实例被当作页来对待）。</li>
</ul>
<p>当然，您自己的应用程序可以使用这些方式的组合。</p>
<br />
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" />
<br />
<img src="http://www.ibm.com/i/c.gif" border="0" height="6" alt="" width="8" />
</td>
</tr>
</tbody>
</table>
<table class="no-print" cellspacing="0" border="0" align="right" cellpadding="0">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" height="4" alt="" width="100%" />
<br />
<table cellspacing="0" border="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" alt="" width="16" />
<br />
</td>
<td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#main" class="fbox"><strong>回页首</strong>
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<br />
<p><a name="5"><span class="atitle">创建外部方法</span>
</a>
</p>
<p>
从 Zope 调用 Python 的最简单的方式是把您的 Python
代码做成
        <em>外部方法</em>
。外部方法是被放到 Zope
安装目录下的&ldquo;Extensions&rdquo;目录中的 Python
函数。一旦那里有了这样一个 Python
文件，您就可以转到任意文件夹，选择&ldquo;添加外部方法&rdquo;，并添加调用要使用的函数的变量。然后您就可以往该文件夹中显示调用结果的任意页添加
DTML 字段。我们来看一个使用了上面所定义的 Python 扩展 ― 
        <code>foo.bar</code>
 ― 的简单示例。
      </p>
<p>首先，来看扩展本身：我们把它放到一个例如叫 
        <code>foo.pyd</code>
 的文件中。记住，这个文件位于 Zope 下的 Extensions 目录。为了能够顺利进行，当然，我们在上面创建的 
        <code>foo.pyd</code>
 必须在位于 bin/lib 的 Python 库中。一个出于这个目的的、简单的包看起来可能像这样:
      </p>
<br />
<a name="code"><strong>清单 3.
一个简单的外部方法（文件：Extensions/foo.py）</strong>
</a>
<br />
 
      
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">import foo
def bar(self,arg):
    &quot;&quot;&quot;A simple external method.&quot;&quot;&quot;
    return 'Arg length: %d' % foo.bar(arg)
</pre>
</td>
</tr>
</tbody>
</table>
<br />
<p>很简单，不是吗？它定义了一个可以用 Zope
管理界面附加到任意文件夹的外部方法&ldquo;bar&rdquo;。要从该文件夹中的任何页中调用我们的扩展，我们只需简单地插入一个
DTML 变量引用，如下所示：</p>
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td class="code-outline">
<pre class="displaycode">  &lt;dtml-var bar('This is a test')&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<br />
<p>当用户查看我们的页时，DTML 字段将被文本&ldquo;Arg length:
14&rdquo;代替。我们就这样用 C 扩展了 Zope。</p>
<br />
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" />
<br />
<img src="http://www.ibm.com/i/c.gif" border="0" height="6" alt="" width="8" />
</td>
</tr>
</tbody>
</table>
<table class="no-print" cellspacing="0" border="0" align="right" cellpadding="0">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" height="4" alt="" width="100%" />
<br />
<table cellspacing="0" border="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" alt="" width="16" />
<br />
</td>
<td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#main" class="fbox"><strong>回页首</strong>
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<br />
<p><a name="6"><span class="atitle">Zope 脚本：Cliff Notes 版</span>
</a>
</p>
<p>
Zope 脚本是 Python 2.3
的一个想用来代替外部方法的新功能。外部方法能做到的，它都能做到，而且它能和安全性及管理系统更好地集成，在集成方面提供更多的灵活性，它还有很多对
Zope API 中公开的全部 Zope 功能的访问。</p>
<p>一个脚本基本上就是一个短小的 Python
程序。它可以定义类或函数，但不是必须的。它被作为对象安装在 Zope
文件夹中，然后就可以把它当作 DTML
变量或调用（就像一个外部方法）来调用或者&ldquo;从 Web 中&rdquo;（在 Zope
中的意思就是它将被当作页来调用）调用它。当然，这意味着脚本可以像
CGI 程序那样生成对表单提交的响应，但却没有 CGI
的开销。确实是一个很棒的功能。此外，脚本有权访问被调用者或调用者对象（通过&ldquo;context&rdquo;对象）、对象所在的文件夹（通过&ldquo;container&rdquo;对象）和其他一些零碎信息。要获得更多关于脚本的知识，请参阅
Zope 手册（请参阅
        <a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#resources">参考资料</a>
）中的&ldquo;高级 Zope
脚本编制（Advanced Zope Scripting）&rdquo;那一章。
      </p>
<p>您可能会错误地认为可以直接从脚本简单地导入 foo 并使用
foo.bar（我知道我确实犯过这种错误）。但事实并非如此。由于安全性限制，只有
Product 可以被导入，而不是什么模块都可以。一般而言，Zope
的设计者们认为任何脚本编制都需要访问文件系统，既然脚本对象是由 Web
使用 Zope
管理界面来管理，所以它们不是完全可信的。所以我打算就此打住，不给您展示示例脚本了，而是来讨论
Product 和基础类。</p>
<br />
<table cellspacing="0" border="0" width="100%" cellpadding="0">
<tbody>
<tr>
<td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" width="100%" />
<br />
<img src="http://www.ibm.com/i/c.gif" border="0" height="6" alt="" width="8" />
</td>
</tr>
</tbody>
</table>
<table class="no-print" cellspacing="0" border="0" align="right" cellpadding="0">
<tbody>
<tr align="right">
<td><img src="http://www.ibm.com/i/c.gif" height="4" alt="" width="100%" />
<br />
<table cellspacing="0" border="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" alt="" width="16" />
<br />
</td>
<td align="right" valign="top"><a href="http://www.ibm.com/developerworks/cn/linux/sdk/python/pyzo/index.html#main" class="fbox"><strong>回页首</strong>
</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<br />
<p><a name="7"><span class="atitle">专注于 Product</span>
</a>
</p>
<p>
Product 是扩展 Zope 的强大工具方法。从安装目录的级别来看，Product
就是位于 Zope
目录下的&ldquo;lib/python/Products&rdquo;目录中的一个目录。在您自己的 Zope
安装目录中，您可以看