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

<channel>
	<title>Basil</title>
	<atom:link href="http://www.basilwang.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.basilwang.net</link>
	<description>又一个 WordPress 站点</description>
	<lastBuildDate>Fri, 10 Feb 2012 09:06:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>windows下调试android源代码</title>
		<link>http://www.basilwang.net/2012/02/window_debug_android_source_code/</link>
		<comments>http://www.basilwang.net/2012/02/window_debug_android_source_code/#comments</comments>
		<pubDate>Fri, 10 Feb 2012 09:02:32 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[android]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2012/02/windows%e4%b8%8b%e8%b0%83%e8%af%95android%e6%ba%90%e4%bb%a3%e7%a0%81/</guid>
		<description><![CDATA[<p>android开发中，因为网上的资料较少，查看android源代码很有必要，那我们怎么才能在android开发中调试android源代码呢？经过笔者的不断尝试，给出了windows下调试android源代码的方案，此方案只是临时替代方案，稍显繁琐，还是希望官方能早点给出调试android源代码的解决方案。</p> <p>本文参考了<a href="http://www.williamhua.com/">William Hua</a>的<a href="http://www.williamhua.com/2009/06/add-android-sourcecode-to-the-sdk/">把Android源代码加入SDK(Updated)</a>以及<a href="http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/">Eric Burke</a>的<a href="http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/">Browsing Android Source in Eclipse</a></p> <p>一.配置环境</p> <p>笔记本：Thinkpad T400 Intel Core 2 Duo P8400 2.26GHz</p> <p>内存：6GB DDR3</p> <p>OS ： Window 7 Professional 64</p> <p>Eclipse : Indigo (Java EE)</p> <p>二 下载Android源代码</p> <p>这里提醒一下，window下无法使用repo（<strong>因为Android是由kernel、Dalvik、Bionic、prebuilt、build等多个Git项目组成，所以Android项目编写了一个名为Repo的Python的脚本来统一管理这些项目的仓库，使得Git的使用更加简单 引自</strong><a href="http://ligux.com/t-321-1-1.html">syles发布，新手扫盲贴之一什么是GIT和REPO</a>），所以推荐使用ubuntu或者macox下载Android源代码，我就是把我在<a href="http://www.basilwang.net/2012/01/mac_os_snow_leopard_build_android_2_3_3_sourcecode/">Mac OS 10.6(Snow Leopard)编译Android源代码</a>一文中下载的源代码拷贝到window中。当然，window中下载Android源代码也不是不可以，不过需要使用git命令独立的下载每个git包，或者参考网上的批处理文件（我担心由于android版本的升级，会导致批处理文件失效，未尝试，也请有经验的网友指点）。</p> <p>三 关联Android源代码</p> <p>由于Android Eclipse plugin (ADT)不允许我们在项目属性中attach源代码到android.jar上，好在<a href="http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/">Eric Burke找到了把source加入到SDK中的办法</a>，通过分析ADT的源代码我们知道ADT是从SDK目录下的<strong>“sources”</strong>目录来查找class对应的源代码，这样我们只要把源代码放到sources目录中ADT就可以自动找到对应的源代码了。</p> <p>另外Android源代码包含在不同的目录中，而放到sources文件夹下的源代码应该按照包名以文件夹的形式组织，好在<a href="http://www.williamhua.com/">William Hua</a>写了一个<a href="http://www.williamhua.com/wp-content/uploads/2009/06/fix_android_sdk.py">py脚本</a>，不过我在使用这个py脚本的时候碰到了一些问题，自己改了一下。</p> <p>主要问题是,在生成文件时报gbk codec错误</p> <p><a href="http://www.basilwang.net/wp-content/uploads/2012/02/gbkerror.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="gbkerror" src="http://www.basilwang.net/wp-content/uploads/2012/02/gbkerror_thumb.png" border="0" alt="gbkerror" width="807" height="151" /></a></p> <p>估计有几个文件里有特殊的字符，造成py脚本中断退出，这里我用了个笨办法，吃掉UnicodeDecodeError异常，这样保证py脚本会生成所有的java文件，除了（产生UnicodeDecodeError的文件，我用的是2.3.3 gingerbread版本，应该有3-4个有问题的java,暂时用不到，不管他）</p> <p>with open(source) as f: <br /><span style="color: #ff0000;"> try: <br /></span> for line in f: <br /> match = re.match(r'\s*package\s+([a-zA-Z0-9\._]+);', line) <br /> if match: <br /> package_path = match.group(1).replace('.', os.sep) <br /> try: <br /> os.makedirs(os.path.join(sources, package_path)) <br /> except os.error: <br /> pass <br /> destination = os.path.join(sources, package_path, filename) <br /> if destination not in written: <br /> written[destination] = True <br /> shutil.copy(source, destination) <br /> break <br /> <span style="color: #ff0000;"> except UnicodeDecodeError: <br /> print(source)</span></p> <p><span style="color: #ff0000;"><span style="color: #000000;">另外我用的是python 3.1.1，需要把原有py脚本的print命令加上括号，python我是新手，自己摸索的</span></span></p> <p><span style="color: #ff0000;"><span style="color: #000000;">使用方法</span></span></p> <p>fix_android_sdk.py &#60; android-source &#62; &#60; android-sdk &#62;</p> <p>比如我的&#60;android-source&#62;是 c:\android   &#60;android-sdk&#62;是 c:\android\android-sdk</p> <p>则写法应该是 fix_android_sdk.py c:\\android  c:\\android\\android-sdk</p> <p>最后在eclipse中Java Source Attachment中指向生成的路径</p> <p><a href="http://www.basilwang.net/wp-content/uploads/2012/02/androidbuildpath.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="androidbuildpath" src="http://www.basilwang.net/wp-content/uploads/2012/02/androidbuildpath_thumb.png" border="0" alt="androidbuildpath" width="729" height="212" /></a></p> <p>最后我们即可在eclipse中看到源代码</p> <p><a href="http://www.basilwang.net/wp-content/uploads/2012/02/activitysource.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="activitysource" src="http://www.basilwang.net/wp-content/uploads/2012/02/activitysource_thumb.png" border="0" alt="activitysource" width="639" height="302" /></a></p> <p>修改后的<a href="http://files.cnblogs.com/basilwang/fix_android_sdk.zip">fix_android_sdk.py下载地址</a></p>]]></description>
			<content:encoded><![CDATA[<p>android开发中，因为网上的资料较少，查看android源代码很有必要，那我们怎么才能在android开发中调试android源代码呢？经过笔者的不断尝试，给出了windows下调试android源代码的方案，此方案只是临时替代方案，稍显繁琐，还是希望官方能早点给出调试android源代码的解决方案。</p>
<p>本文参考了<a href="http://www.williamhua.com/">William Hua</a>的<a href="http://www.williamhua.com/2009/06/add-android-sourcecode-to-the-sdk/">把Android源代码加入SDK(Updated)</a>以及<a href="http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/">Eric Burke</a>的<a href="http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/">Browsing Android Source in Eclipse</a></p>
<p>一.配置环境</p>
<p>笔记本：Thinkpad T400 Intel Core 2 Duo P8400 2.26GHz</p>
<p>内存：6GB DDR3</p>
<p>OS ： Window 7 Professional 64</p>
<p>Eclipse : Indigo (Java EE)</p>
<p>二 下载Android源代码</p>
<p>这里提醒一下，window下无法使用repo（<strong>因为Android是由kernel、Dalvik、Bionic、prebuilt、build等多个Git项目组成，所以Android项目编写了一个名为Repo的Python的脚本来统一管理这些项目的仓库，使得Git的使用更加简单 引自</strong><a href="http://ligux.com/t-321-1-1.html">syles发布，新手扫盲贴之一什么是GIT和REPO</a>），所以推荐使用ubuntu或者macox下载Android源代码，我就是把我在<a href="http://www.basilwang.net/2012/01/mac_os_snow_leopard_build_android_2_3_3_sourcecode/">Mac OS 10.6(Snow Leopard)编译Android源代码</a>一文中下载的源代码拷贝到window中。当然，window中下载Android源代码也不是不可以，不过需要使用git命令独立的下载每个git包，或者参考网上的批处理文件（我担心由于android版本的升级，会导致批处理文件失效，未尝试，也请有经验的网友指点）。</p>
<p>三 关联Android源代码</p>
<p>由于Android Eclipse plugin (ADT)不允许我们在项目属性中attach源代码到android.jar上，好在<a href="http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/">Eric Burke找到了把source加入到SDK中的办法</a>，通过分析ADT的源代码我们知道ADT是从SDK目录下的<strong>“sources”</strong>目录来查找class对应的源代码，这样我们只要把源代码放到sources目录中ADT就可以自动找到对应的源代码了。</p>
<p>另外Android源代码包含在不同的目录中，而放到sources文件夹下的源代码应该按照包名以文件夹的形式组织，好在<a href="http://www.williamhua.com/">William Hua</a>写了一个<a href="http://www.williamhua.com/wp-content/uploads/2009/06/fix_android_sdk.py">py脚本</a>，不过我在使用这个py脚本的时候碰到了一些问题，自己改了一下。</p>
<p>主要问题是,在生成文件时报gbk codec错误</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2012/02/gbkerror.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="gbkerror" src="http://www.basilwang.net/wp-content/uploads/2012/02/gbkerror_thumb.png" border="0" alt="gbkerror" width="807" height="151" /></a></p>
<p>估计有几个文件里有特殊的字符，造成py脚本中断退出，这里我用了个笨办法，吃掉UnicodeDecodeError异常，这样保证py脚本会生成所有的java文件，除了（产生UnicodeDecodeError的文件，我用的是2.3.3 gingerbread版本，应该有3-4个有问题的java,暂时用不到，不管他）</p>
<p>with open(source) as f: <br /><span style="color: #ff0000;"> try: <br /></span> for line in f: <br /> match = re.match(r&#8217;\s*package\s+([a-zA-Z0-9\._]+);&#8217;, line) <br /> if match: <br /> package_path = match.group(1).replace(&#8216;.&#8217;, os.sep) <br /> try: <br /> os.makedirs(os.path.join(sources, package_path)) <br /> except os.error: <br /> pass <br /> destination = os.path.join(sources, package_path, filename) <br /> if destination not in written: <br /> written[destination] = True <br /> shutil.copy(source, destination) <br /> break <br /> <span style="color: #ff0000;"> except UnicodeDecodeError: <br /> print(source)</span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">另外我用的是python 3.1.1，需要把原有py脚本的print命令加上括号，python我是新手，自己摸索的</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">使用方法</span></span></p>
<p>fix_android_sdk.py &lt; android-source &gt; &lt; android-sdk &gt;</p>
<p>比如我的&lt;android-source&gt;是 c:\android   &lt;android-sdk&gt;是 c:\android\android-sdk</p>
<p>则写法应该是 fix_android_sdk.py c:\\android  c:\\android\\android-sdk</p>
<p>最后在eclipse中Java Source Attachment中指向生成的路径</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2012/02/androidbuildpath.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="androidbuildpath" src="http://www.basilwang.net/wp-content/uploads/2012/02/androidbuildpath_thumb.png" border="0" alt="androidbuildpath" width="729" height="212" /></a></p>
<p>最后我们即可在eclipse中看到源代码</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2012/02/activitysource.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="activitysource" src="http://www.basilwang.net/wp-content/uploads/2012/02/activitysource_thumb.png" border="0" alt="activitysource" width="639" height="302" /></a></p>
<p>修改后的<a href="http://files.cnblogs.com/basilwang/fix_android_sdk.zip">fix_android_sdk.py下载地址</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2012/02/window_debug_android_source_code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mac OS 10.6(Snow Leopard)编译Android源代码</title>
		<link>http://www.basilwang.net/2012/01/mac_os_snow_leopard_build_android_2_3_3_sourcecode/</link>
		<comments>http://www.basilwang.net/2012/01/mac_os_snow_leopard_build_android_2_3_3_sourcecode/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 09:50:30 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[android源代码]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2012/01/mac-os-10-6snow-leopard%e7%bc%96%e8%af%91android%e6%ba%90%e4%bb%a3%e7%a0%81/</guid>
		<description><![CDATA[最近在看<a href="http://product.dangdang.com/product.aspx?product_id=22499955">Android内核剖析（柯元丹著）</a>，准备把Android源代码研究一下。做net开发时，就是通过microsoft symbol server取得net framework的源代码加载到debugger调试程序的，这种方式对于框架的学习是最方便不过的。很多时候，我也养成了习惯了随手打开源文件而不是API文档的习惯。Android源代码需要在*nix系统下编译，正好手头有个macbook,于是打算在Mac OS下编译。本文参考了android官网以及部分网友的blog，文中如引用均给已出相应连接。

一.配置环境

笔记本：Macbook MC207CH/A  2.26GHz Intel Core 2 Duo

内存：2GB 1067MHz DDR3

OS ： Snow Leopard 10.6

XCode :  4.0 with ios sdk 4.2 (有问题，后面有解决方案）

JDK ： 1.6

Eclipse :  Indigo (Java EE)

二.设置Mac OS 编译环境

参照官网<a href="http://source.android.com/source/initializing.html">Setting up a Mac OS X build environment</a>，不再赘述。

1.特别强调Android源代码必须在大小写敏感的文件系统下编译，而Mac OS默认不是大小写敏感的，因此需要创建一个大小写敏感的磁盘镜像文件。

具体方法进入应用程序/实用工具/磁盘工具，选择文件-&#62;新建-&#62;新建空白映像：

<a href="http://www.basilwang.net/wp-content/uploads/2012/01/2012-01-31-04.06.38.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="屏幕快照 2012-01-31 下午04.06.38" src="http://www.basilwang.net/wp-content/uploads/2012/01/2012-01-31-04.06.38_thumb.png" border="0" alt="屏幕快照 2012-01-31 下午04.06.38" width="474" height="360" /></a>

2. 使用make 3.81 (revert from make3.82)

强调在mkdir /Users/Shared/dports后<span style="color: #ff0000;">需要使用cd /Users/Shared/dports切换到该文件夹下</span>执行svn co,这里我刚开始没有注意无法安装gmake 3.81

三. 下载Android源代码

参照官网<a href="http://source.android.com/source/downloading.html">Downloading the Source Tree</a>

1. 特别强调在Initializing a Repo client 一节，应该把当前目录设置为前文创建的大小写敏感的文件系统下，比如我把新创建的dmg挂载到/Users/basilwang/android,那么需要执行$cd /Users/basilwang/android  源代码才能放到新创建的这个路径下

我刚开始没有注意，直接执行了

<code>$ repo init -u <a href="https://android.googlesource.com/platform/manifest">https://android.googlesource.com/platform/manifest</a></code>

<code> 结果把源代码下载到其他路径下，白白浪费我2个多小时的时间，而后我把下载的文件扔到了回收站了，结果出了一个错误，害的我又花了一些时间排除这个错误（后面详述）</code>

2. 这里推荐使用<a href="http://product.dangdang.com/product.aspx?product_id=22499955">Android内核剖析（柯元丹著）</a>一书提供的一段防止下载异常的脚本

#!/bin/bash
#FileName <a href="http://get-android.sh/">get-android.sh</a>
PATH=./bin:$PATH
repo init -u <a href="https://android.googlesource.com/platform/manifest">https://android.googlesource.com/platform/manifest</a> -b android-2.3.3_r1.1
repo sync
while [ $? = 1 ]; do
echo "================sync failed, re-sync again ====="
sleep 3
repo sync
done

这里下载的是2.3.3 gingerbread版本

四. 编译Android源代码（Gingerbread）

Gingerbread的编译还依赖于MacOSX10.5.sdk，但本机是10.6，于是下载Xcode 3.25,安装的时候选择另外的路径比如Developer325,安装完毕后Xcode4和Xcode325共存

另外修改两个地方

1 external/qemu/Makefile.android，其中第72行，LEOPARD_SDK:= /Developer/SDKs/MacOSX10.5.sdk，将其修改为：
LEOPARD_SDK:= /Developer325/SDKs/MacOSX10.5.sdk

2 build/core/combo/HOST_darwin-x86.mk,其中第29行，

sdk_105_root := /Developer/SDKs/MacOSX10.5.sdk 改为

sdk_105_root := /Developer325/SDKs/MacOSX10.5.sdk

现在可以开始编译源代码

$make，需要很长时间，我大概用了2个多小时才编译完成

此处报了两个错误，耽误了我很长时间

1 执行make后

find: `frameworks/base/frameworks/base/docs/html': No such file or
directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or
directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or
directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or
directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or
directory
find: `out/target/common/docs/gen': No such file or directory

<img src="http://groups.google.com/groups/img/dot_clear.gif" alt="" width="1" height="1" />

Jean-Baptiste Queru在<a href="http://groups.google.com/group/android-building/browse_thread/thread/dca10d11c5b2f102">Error building Gingerbread?</a>回答

<a name="msg_e3410bc2a570412f">Oh, that error reported by "find" is actually a known harmless issue.
We should add it to the documentation. </a>

2

.Trashes/501/bionic/libc: MODULE.TARGET.STATIC_LIBRARIES.libc_common already defined by bionic/libc.  Stop.

开始我一直在检查为什么会重复定义(already defined)，make clean也不管用，最后发现原来编译时找到了回收站.Trashes我删除过的文件，郁闷，清空回收站就ok.

五.将源代码导入Eclipse

1. 新建Java Project将路径指向Gingerbread目录， 此处为~/android

2. 拷贝.classpath

$sudo cp ~/android/development/ide/eclipse/.classpath   ~/android/.classpath

$chmod +w  ~/android/.classpath    将.classpath设置为可写

3. build 出现如下错误

<a href="http://www.basilwang.net/wp-content/uploads/2012/01/nopackage.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="nopackage" src="http://www.basilwang.net/wp-content/uploads/2012/01/nopackage_thumb.png" border="0" alt="nopackage" width="454" height="490" /></a>

整理报错信息，集中在com.android.common包中

<span style="text-decoration: underline;">com.android.common</span>.ArrayListCursor;

<span style="text-decoration: underline;">com.android.common</span>.speech.LoggingEvents;<span style="text-decoration: underline;">
</span>

<span style="text-decoration: underline;">com.android.common</span>.Rfc822InputFilter;

<span style="text-decoration: underline;">com.android.common</span>.Rfc822Validator;<span style="text-decoration: underline;">
</span>

<span style="text-decoration: underline;">com.android.common</span>.Search;

<span style="text-decoration: underline;">com.android.common</span>.userhappiness.UserHappinessSignals

在Java Build Path界面下

<a href="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="buildpath" src="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath_thumb1.png" border="0" alt="buildpath" width="554" height="334" /></a>

移除出错jar包，并且选择Add JARs 增加<em>out/target/common/obj/JAVA_LIBRARIES/android-common_intermediates/javalib.jar</em>

<em> <a href="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath11.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="buildpath1" src="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath1_thumb1.png" border="0" alt="buildpath1" width="554" height="317" /></a></em>

至此编译成功。]]></description>
			<content:encoded><![CDATA[<p>最近在看<a href="http://product.dangdang.com/product.aspx?product_id=22499955">Android内核剖析（柯元丹著）</a>，准备把Android源代码研究一下。做net开发时，就是通过microsoft symbol server取得net framework的源代码加载到debugger调试程序的，这种方式对于框架的学习是最方便不过的。很多时候，我也养成了习惯了随手打开源文件而不是API文档的习惯。Android源代码需要在*nix系统下编译，正好手头有个macbook,于是打算在Mac OS下编译。本文参考了android官网以及部分网友的blog，文中如引用均给已出相应连接。</p>
<p>一.配置环境</p>
<p>笔记本：Macbook MC207CH/A  2.26GHz Intel Core 2 Duo</p>
<p>内存：2GB 1067MHz DDR3</p>
<p>OS ： Snow Leopard 10.6</p>
<p>XCode :  4.0 with ios sdk 4.2 (有问题，后面有解决方案）</p>
<p>JDK ： 1.6</p>
<p>Eclipse :  Indigo (Java EE)</p>
<p>二.设置Mac OS 编译环境</p>
<p>参照官网<a href="http://source.android.com/source/initializing.html">Setting up a Mac OS X build environment</a>，不再赘述。</p>
<p>1.特别强调Android源代码必须在大小写敏感的文件系统下编译，而Mac OS默认不是大小写敏感的，因此需要创建一个大小写敏感的磁盘镜像文件。</p>
<p>具体方法进入应用程序/实用工具/磁盘工具，选择文件-&gt;新建-&gt;新建空白映像：</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2012/01/2012-01-31-04.06.38.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="屏幕快照 2012-01-31 下午04.06.38" src="http://www.basilwang.net/wp-content/uploads/2012/01/2012-01-31-04.06.38_thumb.png" border="0" alt="屏幕快照 2012-01-31 下午04.06.38" width="474" height="360" /></a></p>
<p>2. 使用make 3.81 (revert from make3.82)</p>
<p>强调在mkdir /Users/Shared/dports后<span style="color: #ff0000;">需要使用cd /Users/Shared/dports切换到该文件夹下</span>执行svn co,这里我刚开始没有注意无法安装gmake 3.81</p>
<p>三. 下载Android源代码</p>
<p>参照官网<a href="http://source.android.com/source/downloading.html">Downloading the Source Tree</a></p>
<p>1. 特别强调在Initializing a Repo client 一节，应该把当前目录设置为前文创建的大小写敏感的文件系统下，比如我把新创建的dmg挂载到/Users/basilwang/android,那么需要执行$cd /Users/basilwang/android  源代码才能放到新创建的这个路径下</p>
<p>我刚开始没有注意，直接执行了</p>
<p><code>$ repo init -u <a href="https://android.googlesource.com/platform/manifest">https://android.googlesource.com/platform/manifest</a></code></p>
<p><code> 结果把源代码下载到其他路径下，白白浪费我2个多小时的时间，而后我把下载的文件扔到了回收站了，结果出了一个错误，害的我又花了一些时间排除这个错误（后面详述）</code></p>
<p>2. 这里推荐使用<a href="http://product.dangdang.com/product.aspx?product_id=22499955">Android内核剖析（柯元丹著）</a>一书提供的一段防止下载异常的脚本</p>
<p>#!/bin/bash<br />
#FileName <a href="http://get-android.sh/">get-android.sh</a><br />
PATH=./bin:$PATH<br />
repo init -u <a href="https://android.googlesource.com/platform/manifest">https://android.googlesource.com/platform/manifest</a> -b android-2.3.3_r1.1<br />
repo sync<br />
while [ $? = 1 ]; do<br />
echo &#8220;================sync failed, re-sync again =====&#8221;<br />
sleep 3<br />
repo sync<br />
done</p>
<p>这里下载的是2.3.3 gingerbread版本</p>
<p>四. 编译Android源代码（Gingerbread）</p>
<p>Gingerbread的编译还依赖于MacOSX10.5.sdk，但本机是10.6，于是下载Xcode 3.25,安装的时候选择另外的路径比如Developer325,安装完毕后Xcode4和Xcode325共存</p>
<p>另外修改两个地方</p>
<p>1 external/qemu/Makefile.android，其中第72行，LEOPARD_SDK:= /Developer/SDKs/MacOSX10.5.sdk，将其修改为：<br />
LEOPARD_SDK:= /Developer325/SDKs/MacOSX10.5.sdk</p>
<p>2 build/core/combo/HOST_darwin-x86.mk,其中第29行，</p>
<p>sdk_105_root := /Developer/SDKs/MacOSX10.5.sdk 改为</p>
<p>sdk_105_root := /Developer325/SDKs/MacOSX10.5.sdk</p>
<p>现在可以开始编译源代码</p>
<p>$make，需要很长时间，我大概用了2个多小时才编译完成</p>
<p>此处报了两个错误，耽误了我很长时间</p>
<p>1 执行make后</p>
<p>find: `frameworks/base/frameworks/base/docs/html&#8217;: No such file or<br />
directory<br />
find: `out/target/common/docs/gen&#8217;: No such file or directory<br />
find: `frameworks/base/frameworks/base/docs/html&#8217;: No such file or<br />
directory<br />
find: `out/target/common/docs/gen&#8217;: No such file or directory<br />
find: `frameworks/base/frameworks/base/docs/html&#8217;: No such file or<br />
directory<br />
find: `out/target/common/docs/gen&#8217;: No such file or directory<br />
find: `frameworks/base/frameworks/base/docs/html&#8217;: No such file or<br />
directory<br />
find: `out/target/common/docs/gen&#8217;: No such file or directory<br />
find: `frameworks/base/frameworks/base/docs/html&#8217;: No such file or<br />
directory<br />
find: `out/target/common/docs/gen&#8217;: No such file or directory</p>
<p><img src="http://groups.google.com/groups/img/dot_clear.gif" alt="" width="1" height="1" /></p>
<p>Jean-Baptiste Queru在<a href="http://groups.google.com/group/android-building/browse_thread/thread/dca10d11c5b2f102">Error building Gingerbread?</a>回答</p>
<p><a name="msg_e3410bc2a570412f">Oh, that error reported by &#8220;find&#8221; is actually a known harmless issue.<br />
We should add it to the documentation. </a></p>
<p>2</p>
<p>.Trashes/501/bionic/libc: MODULE.TARGET.STATIC_LIBRARIES.libc_common already defined by bionic/libc.  Stop.</p>
<p>开始我一直在检查为什么会重复定义(already defined)，make clean也不管用，最后发现原来编译时找到了回收站.Trashes我删除过的文件，郁闷，清空回收站就ok.</p>
<p>五.将源代码导入Eclipse</p>
<p>1. 新建Java Project将路径指向Gingerbread目录， 此处为~/android</p>
<p>2. 拷贝.classpath</p>
<p>$sudo cp ~/android/development/ide/eclipse/.classpath   ~/android/.classpath</p>
<p>$chmod +w  ~/android/.classpath    将.classpath设置为可写</p>
<p>3. build 出现如下错误</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2012/01/nopackage.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="nopackage" src="http://www.basilwang.net/wp-content/uploads/2012/01/nopackage_thumb.png" border="0" alt="nopackage" width="454" height="490" /></a></p>
<p>整理报错信息，集中在com.android.common包中</p>
<p><span style="text-decoration: underline;">com.android.common</span>.ArrayListCursor;</p>
<p><span style="text-decoration: underline;">com.android.common</span>.speech.LoggingEvents;<span style="text-decoration: underline;"><br />
</span></p>
<p><span style="text-decoration: underline;">com.android.common</span>.Rfc822InputFilter;</p>
<p><span style="text-decoration: underline;">com.android.common</span>.Rfc822Validator;<span style="text-decoration: underline;"><br />
</span></p>
<p><span style="text-decoration: underline;">com.android.common</span>.Search;</p>
<p><span style="text-decoration: underline;">com.android.common</span>.userhappiness.UserHappinessSignals</p>
<p>在Java Build Path界面下</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="buildpath" src="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath_thumb1.png" border="0" alt="buildpath" width="554" height="334" /></a></p>
<p>移除出错jar包，并且选择Add JARs 增加<em>out/target/common/obj/JAVA_LIBRARIES/android-common_intermediates/javalib.jar</em></p>
<p><em> <a href="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath11.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="buildpath1" src="http://www.basilwang.net/wp-content/uploads/2012/01/buildpath1_thumb1.png" border="0" alt="buildpath1" width="554" height="317" /></a></em></p>
<p>至此编译成功。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2012/01/mac_os_snow_leopard_build_android_2_3_3_sourcecode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用Mono Runtime Bundle制作安装包让C#桌面应用程序脱离net framework</title>
		<link>http://www.basilwang.net/2011/11/let-your-soft-using-mono-runtime-bundle-while-not-net-framework/</link>
		<comments>http://www.basilwang.net/2011/11/let-your-soft-using-mono-runtime-bundle-while-not-net-framework/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 08:31:32 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[mono]]></category>
		<category><![CDATA[mono mkbundle cygwin monodevelop]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2011/11/%e4%bd%bf%e7%94%a8mono-runtime-bundle%e5%88%b6%e4%bd%9c%e5%ae%89%e8%a3%85%e5%8c%85%e8%ae%a9c%e6%a1%8c%e9%9d%a2%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8f%e8%84%b1%e7%a6%bbnet-framework/</guid>
		<description><![CDATA[<p>之前有一个C#版本和ios版本（支持下载学生名单，点名等更多功能，该版本未上app store)的教辅助手帮助学校老师提交成绩到教务系统（浙大正方web版）,一直打算用mfc写一个vc++版本的可以方便的在未安装net framework的电脑上使用，前几天看到一篇文章<a href="http://www.cnblogs.com/warensoft/archive/2011/07/14/mono.html">再谈为什么要使用MONO</a> ，既然Unity3D游戏(mono内核)可以单独打包脱离net framework,那我的教辅助手一定可以。可是在网上找了一下，中文资料很少，没有讨论具体技术细节的文章（ <a href="http://17zouguo.iteye.com/blog/1168195">让C#程序独立运行(脱离 .NET Framework运行，绿色运行)</a> 是我在移植完成后写教程的时候看到的文章，我的思路和他不太一样，我使用了mkbundle）。</p> <p>教辅助手虽然功能比较简单，但是比hello world还是有技术含量的。我在测试打包的时候使用hello world没有问题，能够脱离net framework正常显示，但如果更复杂的功能和代码以及引入第三方类库的话，到底有没有问题，我心里没底。 实际在我移植的过程中确实碰到很多问题，这个是简单的测试hello world移植所解决不了的。因此我在解决问题后，写下此文记录一下。</p> <p>先说一下教辅助手的功能（由于工作原因无法放出该程序代码），简单点说就是要导入excel成绩表并直接提交到教务系统的页面中，为清楚列表如下</p> <p>1 导入excel成绩表</p> <p>2 提交至web教务系统</p> <p>3 可视界面操作</p> <p>使用的相应技术</p> <p>1 使用System.Data.Oledb访问excel并将取得内容放入System.Data.DataSet</p> <p>2 使用System.Net.HttpWebRequest模拟教务系统登录（该系统使用cookieless方式，所以需要先访问一次得到url中生成的sessionid），然后填入课程相关信息，模拟post提交，使用System.Text.RegularExpressions的正则表达式得到所有学生列表，并根据DataSet内容产生新的Post信息，再次利用post方式提交到教务系统中。</p> <p>3 使用Winform窗口形式</p> <p>相关软件</p> <p>window7 professional&#160; 64bit</p> <p>Cygwin</p> <p>net 2.0/3.5/4.0 framework</p> <p>mono 2.10.6</p> <p>gtk 2.12</p> <p>MonoDevelop 2.8.2</p> <p>下面说一下我的具体过程</p> <p>1 首先使用<a href="http://www.mono-framework.com/MoMA"><em>Mono Migration Analyzer（MoMA)</em></a> 检查已有代码是否可以移植到mono上。我的代码检查通过，但在后继过程发现访问excel功能报错，原因后面会说 。个人感觉MoMA不是很靠谱。</p> <p>2 使用mono编译教辅助手源码。 这里我使用了MonoDeveloper工具，当然也可以使用类似csc.exe的mcs.exe命令行编译方式。不过由于MonoDevelop没有winform的设计器，而且winform是Win32技术，兼容性在Linux下不是很好, mono建议使用GTK#这种第三方的Form技术来做UI，我这里为了使用MonoDeveloper把winform的代码用gtk重写了，用了一个小时吧，代码分层比较好，比较容易剥离。当然如果你习惯csc.exe的命令行方式，而且你的移植后的程序只在window下面运行，那你可以使用mcs.exe并且不需要gtk重写（未尝试此种方式，感觉应该可行，如果哪位朋友有过相关经验，请告知）。</p> <p>使用MonoDevelop要求安装mono和gtk,这里要特别注意的是MonoDevelop可以选择使用net framework还是mono进行编译，开始我没有注意我在MonoDevelop下使用net framework编译运行成功，打包后在mono下运行总是出问题，而且出错信息始终为空，浪费了大量时间。</p> <p>3 在MonoDevelop下选择mono，编译成功后运行失败，报libgda错误，这里解释下问题出现的原因mono下的ole db应该是封装了libgda，而且<a href="http://www.mono-project.com/OLE_DB">mono oledb</a> 支持Sql Server,Oralcle,MySql,SqlLite，不支持Excel；至于为什么不支持Excel,很简单Excel实际上是通过COM访问的（这个是微软的,*nix下不支持）。解决的办法就是不用ole db,于是换用CodePlex上的<a href="http://exceldatareader.codeplex.com/">ExcelDataReader</a>,支持mono，ok。</p> <p>4 MonoDevelop运行时正常而打包后运行时System.Net.HttpWebRequest出错。在运行的时候发现HttpWebRequest无法正常工作，甚至简单的HttpWebRequest.Create(开始怀疑过是cookie container以及url路径问题，均排除，痛苦过程不表)。解决的办法是将machine.config文件一并打包。</p> <p>参见<a href="http://mono.1490590.n4.nabble.com/Issue-with-embedding-machine-config-td1531637.html">Issue with embedding machine.config</a> 实际上我们可以从machine.config发现相关HttpWebRequest的配置信息，该文件路径：mono安装目录\etc\mono\mono版本号\machine.config。</p> <p>5 mkbundle打包。 实际上4和5可以一并说，4中描述的问题导致我频繁的测试mkbundle，尝试加载不同的dll。一度怀疑是打包时dll未正确包含所致，将所需的所有类库lib（system.web.dll、system.net.dll、gac目录等）一并拷贝到运行目录下，仍报错且无任何错误提示，抓狂。这里犯了低级错误检讨一下，mono官网提到mkbundle是一种static linker方式，会将所用到的dll连同应用程序一并embed到一个exe文件中，实际上mkbundle后不再需要类库的dll。</p> <p>mono的mkbundle使用Unix-like <em>toolchain</em>,所以要在window下使用mkbundle需要安装cygwin（同样痛苦的过程），选择gcc-mingw, mingw-zlib, pkg-config,zlib（注意不要选gcc全部安装，网上说有问题我试过也是如此，完全卸掉gcc只选择gcc-mingw), 然后配置cygwin的~/.bashrc文件中配置</p> <p>export PATH=$PATH:/cygdrive/c/Mono-2.6.1/bin<br />export PKG_CONFIG_PATH=/cygdrive/c/Mono-2.10.6/lib/pkgconfig</p> <p>这里参考<a href="http://stackoverflow.com/questions/4474613/can-not-compile-simple-c-sharp-application-with-mkbundle">Can not compile simple C# application with mkbundle</a> 非常详细</p> <p>结合我的实际使用说明一下：</p> <p>无法单独使用mkbundle –o&#160; –-deps 的方式使用mono runtime, 因为mkbundle有一个bug,详见 <a href="http://answerpot.com/showthread.php?1527794-New%3A+mkbundle+fails+due+to+missing+reference+to+g_utf16_to_utf8+(2.8.0%2C+Windows+XP)">New: Mkbundle Fails Due To Missing Reference To G_utf16_to_utf8 (2.8.0, Windows XP)</a> 如果直接使用会报</p> <p>&#160;</p> <p>temp.c: In function `main':<br />temp.c:170: warning: implicit declaration of function `g_utf16_to_utf8'<br />temp.c:170: warning: assignment makes pointer from integer without a cast<br />temp.c:185: warning: assignment makes pointer from integer without a cast<br />/tmp/ccgvpEs0.o: In function `main':<br />/cygdrive/d/paco/jpegp4d-deploy/temp.c:170: undefined reference to<br />`_g_utf16_to_<br />utf8'<br />/cygdrive/d/paco/jpegp4d-deploy/temp.c:185: undefined reference to<br />`_g_utf16_to_<br />utf8'<br />collect2: ld returned 1 exit status<br />[Fail]</p> <p>因此采用mkbundle -c（<font color="#ff0000">更新2012-01-12：在cmd中执行</font><font color="#000000">）</font>和gcc -mno-cygwin（<font color="#ff0000">更新2012-01-12：在cygwin中执行</font><font color="#000000">）</font>的结合的方式</p> <p>以下引自<a href="http://stackoverflow.com/questions/4474613/can-not-compile-simple-c-sharp-application-with-mkbundle">Can not compile simple C# application with mkbundle</a> ，感谢<a href="http://stackoverflow.com/users/458139/lavir-the-whiolet">Lavir the Whiolet</a></p> <ul> <li> <ul> <li>执行: "<code>mkbundle -c -o host.c -oo bundle.o --deps YourAssembly.exe &#60;additional arguments&#62;</code>". 可选-z进行压缩. 完成后得到host.c和bundle.o文件.  <li>在host.c文件中移除_WIN32。增加<code>#undef _WIN32</code>如下: <pre><code>#ifdef _WIN32<br /></code><code>#include &#60;windows.h&#62;<br />#endif</code></pre>
<li>
<p>得到:<br /><code>#ifdef _WIN32<br />#include &#60;windows.h&#62;<br />#endif<br />#undef _WIN32</code></p>
<li>执行: "<code>gcc -mno-cygwin -o ResultantBundle.exe -Wall host.c</code><code>`pkg-config --cflags --libs mono-2&#124;dos2unix`</code> <code>bundle.o &#60;additional arguments&#62;</code>". 如果你mkbundle 加了-z参数, 你必须在这步增加 –lz </li></ul></li></ul>
<p>我的补充</p>
<p>(1) 执行mkbundle是需要embed machine.config的话 增加—machine.config C:\Mono-2.10.6\etc\mono\4.0\machine.config，参考<a href="http://www.mono-project.com/Guide%3ARunning_Mono_Applications#bundles">mono project bundles</a></p>
<p>(2) 如果引入第三方dll的话（比如我使用了第三方ExcelDataReader的excel.dll), 应该加到mkbundle 的&#60;additional arguments&#62;位置,参考<a href="http://razor.occams.info/blog/2006/11/29/embedding-a-javascript-interpreter-with-mono/">Embedding a JavaScript interpreter with Mono</a></p>
<p>以我的mkbundle和gcc为例</p>
<p><strike>mkbundle –c –o host.c –oo bundle.o –deps myProgram.exe Excel.dll&#160; --machine-config C:\Mono-2.10.6\etc\mono\4.0\machine.config</strike></p>
<p><font color="#ff0000">更新(2012-01-12)：</font></p>
<p><font color="#ff0000">mkbundle -c -o host.c -oo bundle.o --deps MonoTA.exe Excel.dll -z&#160; --machine-config C:\Mono-2.10.6\etc\mono\4.0\machine.config</font></p>
<p><font color="#ff0000">gcc -mno-cygwin -o MonoTARelease.exe -Wall host.c `pkg-config --cflags --libs mono-2&#124;dos2unix` bundle.o -lz</font><br /></p>
<p>6 发布</p>
<p>生成的exe文件已经embed mono runtime了，我的应用程序原来32k，使用-z压缩生成后是5MB，有点大不过可以接受。但要脱离net framework在window上执行，还需要调用几个文件，罗列如下（针对mono4.0,我一个个找的，是不是可以做个工具自动查找依赖?）</p>
<p>freetype6.dll<br />glibsharpglue-2.dll<br />gtksharpglue-2.dll<br />intl.dll<br />libatk-1.0-0.dll<br />libcairo-2.dll<br />libexpat-1.dll<br />libfontconfig-1.dll<br />libgdk_pixbuf-2.0-0.dll<br />libgdk-win32-2.0-0.dll<br />libgio-2.0-0.dll<br />libglib-2.0-0.dll<br />libgmodule-2.0-0.dll<br />libgobject-2.0-0.dll<br />libgthread-2.0-0.dll<br />libgtk-win32-2.0-0.dll<br />libpango-1.0-0.dll<br />libpangocairo-1.0-0.dll<br />libpangoft2-1.0-0.dll<br />libpangowin32-1.0-0.dll<br />libpng14-14.dll<br />mono-2.0.dll<br />MonoPosixHelper.dll<br />zlib1.dll</p>
<p>总共16.9MB</p>
<p>7 后记</p>
<p>个人感觉，虽然过程曲折了点，但使用mono runtime让软件脱离net framework是完全可行的，而且应该是可以用到生产环境的，也希望mono越来越好。</p>]]></description>
			<content:encoded><![CDATA[<p>之前有一个C#版本和ios版本（支持下载学生名单，点名等更多功能，该版本未上app store)的教辅助手帮助学校老师提交成绩到教务系统（浙大正方web版）,一直打算用mfc写一个vc++版本的可以方便的在未安装net framework的电脑上使用，前几天看到一篇文章<a href="http://www.cnblogs.com/warensoft/archive/2011/07/14/mono.html">再谈为什么要使用MONO</a> ，既然Unity3D游戏(mono内核)可以单独打包脱离net framework,那我的教辅助手一定可以。可是在网上找了一下，中文资料很少，没有讨论具体技术细节的文章（ <a href="http://17zouguo.iteye.com/blog/1168195">让C#程序独立运行(脱离 .NET Framework运行，绿色运行)</a> 是我在移植完成后写教程的时候看到的文章，我的思路和他不太一样，我使用了mkbundle）。</p>
<p>教辅助手虽然功能比较简单，但是比hello world还是有技术含量的。我在测试打包的时候使用hello world没有问题，能够脱离net framework正常显示，但如果更复杂的功能和代码以及引入第三方类库的话，到底有没有问题，我心里没底。 实际在我移植的过程中确实碰到很多问题，这个是简单的测试hello world移植所解决不了的。因此我在解决问题后，写下此文记录一下。</p>
<p>先说一下教辅助手的功能（由于工作原因无法放出该程序代码），简单点说就是要导入excel成绩表并直接提交到教务系统的页面中，为清楚列表如下</p>
<p>1 导入excel成绩表</p>
<p>2 提交至web教务系统</p>
<p>3 可视界面操作</p>
<p>使用的相应技术</p>
<p>1 使用System.Data.Oledb访问excel并将取得内容放入System.Data.DataSet</p>
<p>2 使用System.Net.HttpWebRequest模拟教务系统登录（该系统使用cookieless方式，所以需要先访问一次得到url中生成的sessionid），然后填入课程相关信息，模拟post提交，使用System.Text.RegularExpressions的正则表达式得到所有学生列表，并根据DataSet内容产生新的Post信息，再次利用post方式提交到教务系统中。</p>
<p>3 使用Winform窗口形式</p>
<p>相关软件</p>
<p>window7 professional&nbsp; 64bit</p>
<p>Cygwin</p>
<p>net 2.0/3.5/4.0 framework</p>
<p>mono 2.10.6</p>
<p>gtk 2.12</p>
<p>MonoDevelop 2.8.2</p>
<p>下面说一下我的具体过程</p>
<p>1 首先使用<a href="http://www.mono-framework.com/MoMA"><em>Mono Migration Analyzer（MoMA)</em></a> 检查已有代码是否可以移植到mono上。我的代码检查通过，但在后继过程发现访问excel功能报错，原因后面会说 。个人感觉MoMA不是很靠谱。</p>
<p>2 使用mono编译教辅助手源码。 这里我使用了MonoDeveloper工具，当然也可以使用类似csc.exe的mcs.exe命令行编译方式。不过由于MonoDevelop没有winform的设计器，而且winform是Win32技术，兼容性在Linux下不是很好, mono建议使用GTK#这种第三方的Form技术来做UI，我这里为了使用MonoDeveloper把winform的代码用gtk重写了，用了一个小时吧，代码分层比较好，比较容易剥离。当然如果你习惯csc.exe的命令行方式，而且你的移植后的程序只在window下面运行，那你可以使用mcs.exe并且不需要gtk重写（未尝试此种方式，感觉应该可行，如果哪位朋友有过相关经验，请告知）。</p>
<p>使用MonoDevelop要求安装mono和gtk,这里要特别注意的是MonoDevelop可以选择使用net framework还是mono进行编译，开始我没有注意我在MonoDevelop下使用net framework编译运行成功，打包后在mono下运行总是出问题，而且出错信息始终为空，浪费了大量时间。</p>
<p>3 在MonoDevelop下选择mono，编译成功后运行失败，报libgda错误，这里解释下问题出现的原因mono下的ole db应该是封装了libgda，而且<a href="http://www.mono-project.com/OLE_DB">mono oledb</a> 支持Sql Server,Oralcle,MySql,SqlLite，不支持Excel；至于为什么不支持Excel,很简单Excel实际上是通过COM访问的（这个是微软的,*nix下不支持）。解决的办法就是不用ole db,于是换用CodePlex上的<a href="http://exceldatareader.codeplex.com/">ExcelDataReader</a>,支持mono，ok。</p>
<p>4 MonoDevelop运行时正常而打包后运行时System.Net.HttpWebRequest出错。在运行的时候发现HttpWebRequest无法正常工作，甚至简单的HttpWebRequest.Create(开始怀疑过是cookie container以及url路径问题，均排除，痛苦过程不表)。解决的办法是将machine.config文件一并打包。</p>
<p>参见<a href="http://mono.1490590.n4.nabble.com/Issue-with-embedding-machine-config-td1531637.html">Issue with embedding machine.config</a> 实际上我们可以从machine.config发现相关HttpWebRequest的配置信息，该文件路径：mono安装目录\etc\mono\mono版本号\machine.config。</p>
<p>5 mkbundle打包。 实际上4和5可以一并说，4中描述的问题导致我频繁的测试mkbundle，尝试加载不同的dll。一度怀疑是打包时dll未正确包含所致，将所需的所有类库lib（system.web.dll、system.net.dll、gac目录等）一并拷贝到运行目录下，仍报错且无任何错误提示，抓狂。这里犯了低级错误检讨一下，mono官网提到mkbundle是一种static linker方式，会将所用到的dll连同应用程序一并embed到一个exe文件中，实际上mkbundle后不再需要类库的dll。</p>
<p>mono的mkbundle使用Unix-like <em>toolchain</em>,所以要在window下使用mkbundle需要安装cygwin（同样痛苦的过程），选择gcc-mingw, mingw-zlib, pkg-config,zlib（注意不要选gcc全部安装，网上说有问题我试过也是如此，完全卸掉gcc只选择gcc-mingw), 然后配置cygwin的~/.bashrc文件中配置</p>
<p>export PATH=$PATH:/cygdrive/c/Mono-2.6.1/bin<br />export PKG_CONFIG_PATH=/cygdrive/c/Mono-2.10.6/lib/pkgconfig</p>
<p>这里参考<a href="http://stackoverflow.com/questions/4474613/can-not-compile-simple-c-sharp-application-with-mkbundle">Can not compile simple C# application with mkbundle</a> 非常详细</p>
<p>结合我的实际使用说明一下：</p>
<p>无法单独使用mkbundle –o&nbsp; –-deps 的方式使用mono runtime, 因为mkbundle有一个bug,详见 <a href="http://answerpot.com/showthread.php?1527794-New%3A+mkbundle+fails+due+to+missing+reference+to+g_utf16_to_utf8+(2.8.0%2C+Windows+XP)">New: Mkbundle Fails Due To Missing Reference To G_utf16_to_utf8 (2.8.0, Windows XP)</a> 如果直接使用会报</p>
<p>&nbsp;</p>
<p>temp.c: In function `main&#8217;:<br />temp.c:170: warning: implicit declaration of function `g_utf16_to_utf8&#8242;<br />temp.c:170: warning: assignment makes pointer from integer without a cast<br />temp.c:185: warning: assignment makes pointer from integer without a cast<br />/tmp/ccgvpEs0.o: In function `main&#8217;:<br />/cygdrive/d/paco/jpegp4d-deploy/temp.c:170: undefined reference to<br />`_g_utf16_to_<br />utf8&#8242;<br />/cygdrive/d/paco/jpegp4d-deploy/temp.c:185: undefined reference to<br />`_g_utf16_to_<br />utf8&#8242;<br />collect2: ld returned 1 exit status<br />[Fail]</p>
<p>因此采用mkbundle -c（<font color="#ff0000">更新2012-01-12：在cmd中执行</font><font color="#000000">）</font>和gcc -mno-cygwin（<font color="#ff0000">更新2012-01-12：在cygwin中执行</font><font color="#000000">）</font>的结合的方式</p>
<p>以下引自<a href="http://stackoverflow.com/questions/4474613/can-not-compile-simple-c-sharp-application-with-mkbundle">Can not compile simple C# application with mkbundle</a> ，感谢<a href="http://stackoverflow.com/users/458139/lavir-the-whiolet">Lavir the Whiolet</a></p>
<ul>
<li>
<ul>
<li>执行: &#8220;<code>mkbundle -c -o host.c -oo bundle.o --deps YourAssembly.exe &lt;additional arguments&gt;</code>&#8220;. 可选-z进行压缩. 完成后得到host.c和bundle.o文件.
<li>在host.c文件中移除_WIN32。增加<code>#undef _WIN32</code>如下:
<pre><code>#ifdef _WIN32</code><code>#include &lt;windows.h&gt;#endif</code></pre>
<li>
<p>得到:<br /><code>#ifdef _WIN32<br />#include &lt;windows.h&gt;<br />#endif<br />#undef _WIN32</code></p>
<li>执行: &#8220;<code>gcc -mno-cygwin -o ResultantBundle.exe -Wall host.c</code><code>`pkg-config --cflags --libs mono-2|dos2unix`</code> <code>bundle.o &lt;additional arguments&gt;</code>&#8220;. 如果你mkbundle 加了-z参数, 你必须在这步增加 –lz </li>
</ul>
</li>
</ul>
<p>我的补充</p>
<p>(1) 执行mkbundle是需要embed machine.config的话 增加—machine.config C:\Mono-2.10.6\etc\mono\4.0\machine.config，参考<a href="http://www.mono-project.com/Guide%3ARunning_Mono_Applications#bundles">mono project bundles</a></p>
<p>(2) 如果引入第三方dll的话（比如我使用了第三方ExcelDataReader的excel.dll), 应该加到mkbundle 的&lt;additional arguments&gt;位置,参考<a href="http://razor.occams.info/blog/2006/11/29/embedding-a-javascript-interpreter-with-mono/">Embedding a JavaScript interpreter with Mono</a></p>
<p>以我的mkbundle和gcc为例</p>
<p><strike>mkbundle –c –o host.c –oo bundle.o –deps myProgram.exe Excel.dll&nbsp; &#8211;machine-config C:\Mono-2.10.6\etc\mono\4.0\machine.config</strike></p>
<p><font color="#ff0000">更新(2012-01-12)：</font></p>
<p><font color="#ff0000">mkbundle -c -o host.c -oo bundle.o &#8211;deps MonoTA.exe Excel.dll -z&nbsp; &#8211;machine-config C:\Mono-2.10.6\etc\mono\4.0\machine.config</font></p>
<p><font color="#ff0000">gcc -mno-cygwin -o MonoTARelease.exe -Wall host.c `pkg-config &#8211;cflags &#8211;libs mono-2|dos2unix` bundle.o -lz</font></p>
<p>6 发布</p>
<p>生成的exe文件已经embed mono runtime了，我的应用程序原来32k，使用-z压缩生成后是5MB，有点大不过可以接受。但要脱离net framework在window上执行，还需要调用几个文件，罗列如下（针对mono4.0,我一个个找的，是不是可以做个工具自动查找依赖?）</p>
<p>freetype6.dll<br />glibsharpglue-2.dll<br />gtksharpglue-2.dll<br />intl.dll<br />libatk-1.0-0.dll<br />libcairo-2.dll<br />libexpat-1.dll<br />libfontconfig-1.dll<br />libgdk_pixbuf-2.0-0.dll<br />libgdk-win32-2.0-0.dll<br />libgio-2.0-0.dll<br />libglib-2.0-0.dll<br />libgmodule-2.0-0.dll<br />libgobject-2.0-0.dll<br />libgthread-2.0-0.dll<br />libgtk-win32-2.0-0.dll<br />libpango-1.0-0.dll<br />libpangocairo-1.0-0.dll<br />libpangoft2-1.0-0.dll<br />libpangowin32-1.0-0.dll<br />libpng14-14.dll<br />mono-2.0.dll<br />MonoPosixHelper.dll<br />zlib1.dll</p>
<p>总共16.9MB</p>
<p>7 后记</p>
<p>个人感觉，虽然过程曲折了点，但使用mono runtime让软件脱离net framework是完全可行的，而且应该是可以用到生产环境的，也希望mono越来越好。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2011/11/let-your-soft-using-mono-runtime-bundle-while-not-net-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>c++对象成员函数返回自身引用时出现的诡异问题及解决办法</title>
		<link>http://www.basilwang.net/2010/10/cplusplus-function-return-ref-error/</link>
		<comments>http://www.basilwang.net/2010/10/cplusplus-function-return-ref-error/#comments</comments>
		<pubDate>Thu, 14 Oct 2010 03:39:00 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2010/10/c%e5%af%b9%e8%b1%a1%e6%88%90%e5%91%98%e5%87%bd%e6%95%b0%e8%bf%94%e5%9b%9e%e8%87%aa%e8%ba%ab%e5%bc%95%e7%94%a8%e6%97%b6%e5%87%ba%e7%8e%b0%e7%9a%84%e8%af%a1%e5%bc%82%e9%97%ae%e9%a2%98%e5%8f%8a/</guid>
		<description><![CDATA[<pre class="code">list.h (实际上是数据结构顺序表的一个例子，为了展现问题，我简化了部分代码，只留下插入和打印）</pre>
<p>&#160;</p><pre class="code"><span style="color: blue">#include</span><span style="color: #a31515">&#60;iostream&#62;
</span><span style="color: blue">using namespace </span>std;
<span style="color: blue">class </span>List
{
<span style="color: blue">public</span>:
    List(<span style="color: blue">int </span>max_list_size)
    {
      max_size=max_list_size;
      data=<span style="color: blue">new int</span>[max_size];
      n=0;
    }
    ~List()
    {
        <span style="color: blue">delete</span>[]data;
    }
    <span style="color: blue">bool </span>empty()<span style="color: green">//const
    </span>{
        <span style="color: blue">return </span>n==0;
    }
    <span style="color: blue">int </span>size()
    {
        <span style="color: blue">return </span>n;
    }
    List insert(<span style="color: blue">int </span>k,<span style="color: blue">int </span>&#38;x)
    {
        <span style="color: blue">for</span>(<span style="color: blue">int </span>i=n-1;i&#62;=k;i--)
            data[i+1]=data[i];
        data[k]=x;
        <span style="color: green">//此处有值
        </span>cout&#60;&#60;<span style="color: #a31515">"data inserted phase"</span>&#60;&#60;endl;
        cout&#60;&#60;<span style="color: #a31515">"data[0]="</span>&#60;&#60;data[0]&#60;&#60;endl;
        n++;
        <span style="color: blue">return </span>*<span style="color: blue">this</span>;
    }
    <span style="color: blue">void </span>print_list() <span style="color: green">//const;
    </span>{
      <span style="color: green">//此处没值
      </span>cout&#60;&#60;<span style="color: #a31515">"print phase"</span>&#60;&#60;endl;
      <span style="color: blue">for</span>(<span style="color: blue">int </span>i=0;i&#60;n;i++)
      {
        cout&#60;&#60;<span style="color: #a31515">"data["</span>&#60;&#60;i&#60;&#60;<span style="color: #a31515">"]="</span>&#60;&#60;data[i]&#60;&#60;endl;
      }
    }

<span style="color: blue">private</span>:
    <span style="color: blue">int </span>n;
    <span style="color: blue">int </span>max_size;
    <span style="color: blue">int </span>*data;
};</pre>
<p><br />main函数<br /></p><pre class="code"><span style="color: blue">#include</span><span style="color: #a31515">&#60;iostream&#62;
</span><span style="color: blue">using namespace </span>std;
<span style="color: blue">#include</span><span style="color: #a31515">"List.h"
</span><span style="color: blue">int </span>main()
{

    List list(5);
    <span style="color: blue">int </span>t;
    cout&#60;&#60;<span style="color: #a31515">"please enter a integer and press enter"</span>&#60;&#60;endl;
    cin&#62;&#62;t;
    cout&#60;&#60;t&#60;&#60;endl;
    list.insert(0,t);
    list.print_list();
    system(<span style="color: #a31515">"pause"</span>);
    <span style="color: blue">return </span>0;
}</pre>
<p>运行时输入2 回车 结果如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/result_3.jpg"><img style="display: inline" title="result_3" alt="result_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/result_3_thumb.jpg" width="480" height="276"></a></p>
<p>你能看出问题在哪里吗？</p>
<p>当我把成员函数insert的返回值类型 由 List 改为List &#38; 结果就正确了</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/result1_3.jpg"><img style="display: inline" title="result1_3" alt="result1_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/result1_3_thumb.jpg" width="480" height="254"></a></p>
<p>下面我们分析下出现该问题的原因，以及应对方法</p>
<p>首先大家要了解的是函数的返回值的传递方式，这里大家应该牢记的是函数返回值的传递和函数传递参数的方式是基本一样的，关于函数传递参数的方式请参见<a href="http://www.basilwang.net/?p=528">C++指针存储结构</a>。</p>
<p>函数返回值的传递也分为按值传递和按引用传递两种</p>
<p>示例代码中成员函数insert的函数原型为List insert(int k,int &#38;x) 为按值传递，所以在返回值实际上复制了一个新的对象x，那么这个新的对象和原有的调用该函数的对象（假设为l)有什么区别和联系？</p>
<p>要回答这个问题就要了解一下拷贝构造函数，拷贝构造函数会在<strike><font color="#ff0000">赋值（=）以及</font></strike>函数按值传递参数或者按值传递返回值的时候调用；当类中没有拷贝构造函数时，会调用默认的拷贝构造函数。一般情况下，默认构造函数会对源对象的每个数据成员一一赋值给目标对象的同一数据成员，但如果数据成员包含指针，可能导致严重问题。</p><pre class="code">List list(5);
<span style="color: blue">int </span>t;
cin&#62;&#62;t;    list.insert(0,t);</pre>
<p>当调用list.insert方法时，由于返回值是按值传递的，所以会调用默认拷贝构造函数复制一个新的对象（假设为x)，但由于List类数据成员包含指针，会出现如下情况</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref1_3.jpg"><img style="display: inline" title="ref1_3" alt="ref1_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref1_3_thumb.jpg" width="480" height="204"></a></p>
<p>目前好像看不出什么问题，接下来有问题了，由于该成员函数的返回对象x（实际上是临时对象）并没有赋给任何变量，所以会立即调用析构函数析构掉，析构函数的代码</p><pre class="code">~List()
    {
        <span style="color: blue">delete</span>[]data;
    }</pre>
<p>析构以后如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref2_3.jpg"><img style="display: inline" title="ref2_3" alt="ref2_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref2_3_thumb.jpg" width="480" height="252"></a></p>
<p>此时对象l的data指针却还指向那块被释放掉了的区域，形成了“虚悬引用”，也就是俗称的“野指针”。所以也当查看对象l的data[0]是变成一个奇怪的值。</p>
<p>问题的解决是加上自己的拷贝构造函数</p><pre class="code">List(<span style="color: blue">const </span>List&#38; right):n(right.n),max_size(right.max_size)
{
        data = <span style="color: blue">new int </span>[max_size];
        <span style="color: blue">for </span>(<span style="color: blue">int </span>i=0; i&#60;n;i++)
        {
            data[i]=right.data[i];
        }
}</pre>
<p>此时调用 l.insert时，内存存储示意图如下</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref3_3.jpg"><img style="display: inline" title="ref3_3" alt="ref3_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref3_3_thumb.jpg" width="480" height="198"></a></p>
<p>由于x是临时对象会接着调用析构函数</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref4_3.jpg"><img style="display: inline" title="ref4_3" alt="ref4_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref4_3_thumb.jpg" width="480" height="252"></a></p>
<p>增加了拷贝构造函数只是能够让结果正确的显示，但是在实际开发中，很少采用函数按值返回的形式返回一个对象（相当于赋值一份），浪费了空间不说，还容易造成上述的问题，解决的办法是按引用返回，做如下修改</p><pre class="code">List&#38;  insert(<span style="color: blue">int </span>k,<span style="color: blue">int </span>&#38;x)
    {
        <span style="color: blue">for</span>(<span style="color: blue">int </span>i=n-1;i&#62;=k;i--)
            data[i+1]=data[i];
        data[k]=x;
<span style="color: green">        </span>cout&#60;&#60;<span style="color: #a31515">"data inserted phase"</span>&#60;&#60;endl;
        cout&#60;&#60;<span style="color: #a31515">"data[0]="</span>&#60;&#60;data[0]&#60;&#60;endl;
        n++;
        <span style="color: blue">return </span>*<span style="color: blue">this</span>;
    }</pre>
<p><br />把List改为List&#38; ,引用就相当于一个别名（我的理解是隔山打牛，参见<a href="http://www.basilwang.net/2010/09/cplusplus-pointer-storage-structure/">C++指针存储结构</a>），至此问题解决。</p>]]></description>
			<content:encoded><![CDATA[<pre class="code">list.h (实际上是数据结构顺序表的一个例子，为了展现问题，我简化了部分代码，只留下插入和打印）</pre>
<p>&nbsp;</p>
<pre class="code"><span style="color: blue">#include</span><span style="color: #a31515">&lt;iostream&gt;
</span><span style="color: blue">using namespace </span>std;
<span style="color: blue">class </span>List
{
<span style="color: blue">public</span>:
    List(<span style="color: blue">int </span>max_list_size)
    {
      max_size=max_list_size;
      data=<span style="color: blue">new int</span>[max_size];
      n=0;
    }
    ~List()
    {
        <span style="color: blue">delete</span>[]data;
    }
    <span style="color: blue">bool </span>empty()<span style="color: green">//const
    </span>{
        <span style="color: blue">return </span>n==0;
    }
    <span style="color: blue">int </span>size()
    {
        <span style="color: blue">return </span>n;
    }
    List insert(<span style="color: blue">int </span>k,<span style="color: blue">int </span>&amp;x)
    {
        <span style="color: blue">for</span>(<span style="color: blue">int </span>i=n-1;i&gt;=k;i--)
            data[i+1]=data[i];
        data[k]=x;
        <span style="color: green">//此处有值
        </span>cout&lt;&lt;<span style="color: #a31515">"data inserted phase"</span>&lt;&lt;endl;
        cout&lt;&lt;<span style="color: #a31515">"data[0]="</span>&lt;&lt;data[0]&lt;&lt;endl;
        n++;
        <span style="color: blue">return </span>*<span style="color: blue">this</span>;
    }
    <span style="color: blue">void </span>print_list() <span style="color: green">//const;
    </span>{
      <span style="color: green">//此处没值
      </span>cout&lt;&lt;<span style="color: #a31515">"print phase"</span>&lt;&lt;endl;
      <span style="color: blue">for</span>(<span style="color: blue">int </span>i=0;i&lt;n;i++)
      {
        cout&lt;&lt;<span style="color: #a31515">"data["</span>&lt;&lt;i&lt;&lt;<span style="color: #a31515">"]="</span>&lt;&lt;data[i]&lt;&lt;endl;
      }
    }

<span style="color: blue">private</span>:
    <span style="color: blue">int </span>n;
    <span style="color: blue">int </span>max_size;
    <span style="color: blue">int </span>*data;
};</pre>
<p>main函数</p>
<pre class="code"><span style="color: blue">#include</span><span style="color: #a31515">&lt;iostream&gt;
</span><span style="color: blue">using namespace </span>std;
<span style="color: blue">#include</span><span style="color: #a31515">"List.h"
</span><span style="color: blue">int </span>main()
{

    List list(5);
    <span style="color: blue">int </span>t;
    cout&lt;&lt;<span style="color: #a31515">"please enter a integer and press enter"</span>&lt;&lt;endl;
    cin&gt;&gt;t;
    cout&lt;&lt;t&lt;&lt;endl;
    list.insert(0,t);
    list.print_list();
    system(<span style="color: #a31515">"pause"</span>);
    <span style="color: blue">return </span>0;
}</pre>
<p>运行时输入2 回车 结果如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/result_3.jpg"><img style="display: inline" title="result_3" alt="result_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/result_3_thumb.jpg" width="480" height="276"></a></p>
<p>你能看出问题在哪里吗？</p>
<p>当我把成员函数insert的返回值类型 由 List 改为List &amp; 结果就正确了</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/result1_3.jpg"><img style="display: inline" title="result1_3" alt="result1_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/result1_3_thumb.jpg" width="480" height="254"></a></p>
<p>下面我们分析下出现该问题的原因，以及应对方法</p>
<p>首先大家要了解的是函数的返回值的传递方式，这里大家应该牢记的是函数返回值的传递和函数传递参数的方式是基本一样的，关于函数传递参数的方式请参见<a href="http://www.basilwang.net/?p=528">C++指针存储结构</a>。</p>
<p>函数返回值的传递也分为按值传递和按引用传递两种</p>
<p>示例代码中成员函数insert的函数原型为List insert(int k,int &amp;x) 为按值传递，所以在返回值实际上复制了一个新的对象x，那么这个新的对象和原有的调用该函数的对象（假设为l)有什么区别和联系？</p>
<p>要回答这个问题就要了解一下拷贝构造函数，拷贝构造函数会在<strike><font color="#ff0000">赋值（=）以及</font></strike>函数按值传递参数或者按值传递返回值的时候调用；当类中没有拷贝构造函数时，会调用默认的拷贝构造函数。一般情况下，默认构造函数会对源对象的每个数据成员一一赋值给目标对象的同一数据成员，但如果数据成员包含指针，可能导致严重问题。</p>
<pre class="code">List list(5);
<span style="color: blue">int </span>t;
cin&gt;&gt;t;    list.insert(0,t);</pre>
<p>当调用list.insert方法时，由于返回值是按值传递的，所以会调用默认拷贝构造函数复制一个新的对象（假设为x)，但由于List类数据成员包含指针，会出现如下情况</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref1_3.jpg"><img style="display: inline" title="ref1_3" alt="ref1_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref1_3_thumb.jpg" width="480" height="204"></a></p>
<p>目前好像看不出什么问题，接下来有问题了，由于该成员函数的返回对象x（实际上是临时对象）并没有赋给任何变量，所以会立即调用析构函数析构掉，析构函数的代码</p>
<pre class="code">~List()
    {
        <span style="color: blue">delete</span>[]data;
    }</pre>
<p>析构以后如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref2_3.jpg"><img style="display: inline" title="ref2_3" alt="ref2_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref2_3_thumb.jpg" width="480" height="252"></a></p>
<p>此时对象l的data指针却还指向那块被释放掉了的区域，形成了“虚悬引用”，也就是俗称的“野指针”。所以也当查看对象l的data[0]是变成一个奇怪的值。</p>
<p>问题的解决是加上自己的拷贝构造函数</p>
<pre class="code">List(<span style="color: blue">const </span>List&amp; right):n(right.n),max_size(right.max_size)
{
        data = <span style="color: blue">new int </span>[max_size];
        <span style="color: blue">for </span>(<span style="color: blue">int </span>i=0; i&lt;n;i++)
        {
            data[i]=right.data[i];
        }
}</pre>
<p>此时调用 l.insert时，内存存储示意图如下</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref3_3.jpg"><img style="display: inline" title="ref3_3" alt="ref3_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref3_3_thumb.jpg" width="480" height="198"></a></p>
<p>由于x是临时对象会接着调用析构函数</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/ref4_3.jpg"><img style="display: inline" title="ref4_3" alt="ref4_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/ref4_3_thumb.jpg" width="480" height="252"></a></p>
<p>增加了拷贝构造函数只是能够让结果正确的显示，但是在实际开发中，很少采用函数按值返回的形式返回一个对象（相当于赋值一份），浪费了空间不说，还容易造成上述的问题，解决的办法是按引用返回，做如下修改</p>
<pre class="code">List&amp;  insert(<span style="color: blue">int </span>k,<span style="color: blue">int </span>&amp;x)
    {
        <span style="color: blue">for</span>(<span style="color: blue">int </span>i=n-1;i&gt;=k;i--)
            data[i+1]=data[i];
        data[k]=x;
<span style="color: green">        </span>cout&lt;&lt;<span style="color: #a31515">"data inserted phase"</span>&lt;&lt;endl;
        cout&lt;&lt;<span style="color: #a31515">"data[0]="</span>&lt;&lt;data[0]&lt;&lt;endl;
        n++;
        <span style="color: blue">return </span>*<span style="color: blue">this</span>;
    }</pre>
<p>把List改为List&amp; ,引用就相当于一个别名（我的理解是隔山打牛，参见<a href="http://www.basilwang.net/2010/09/cplusplus-pointer-storage-structure/">C++指针存储结构</a>），至此问题解决。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2010/10/cplusplus-function-return-ref-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++指针存储结构</title>
		<link>http://www.basilwang.net/2010/09/cplusplus-pointer-storage-structure/</link>
		<comments>http://www.basilwang.net/2010/09/cplusplus-pointer-storage-structure/#comments</comments>
		<pubDate>Mon, 20 Sep 2010 03:34:00 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2011/09/c%e6%8c%87%e9%92%88%e5%ad%98%e5%82%a8%e7%bb%93%e6%9e%84/</guid>
		<description><![CDATA[—概述

—线性排序

—二进制存放

—数据类型和编码

—变量和指针

—引用

—数组

—动态存储分配

—函数参数传递在内存中的表示
<h3><strong>概述</strong></h3>
c++的学习中，对指针的理解和把握相当重要，可能很多同学对此感到困惑。我个人感觉指针的理解实际上还是依赖于对内存存储的理解，因此了解内存的存储机制就显得至关重要。

当然由于内存的存储机制实际上比较复杂，而且我们的任务是学习程序的编写，所以我这里更多是从程序的角度来看内存的存储（有一定程度的简化）。但当我们了解了内存存储的方式，知道程序中的常量、变量、指针在内存中的表示，又能够进一步指导我们程序的书写。
<h4>线性排序</h4>
首先请把内存想象成一段连续的格子，每个格子可以存储内容（如果一个格子装不下，可能放到多个格子中，这种情况很普遍）

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/1_1.jpg"><img style="display: inline;" title="1_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/1_1_thumb.jpg" alt="1_1" width="480" height="90" /></a>

注意两点

1 格子是有序排列的，也就是每个格子都有编号，从小到大排列。我们也常说内存是线性空间排列的（就是想象成一条线）

2. 每个格子大小是1个字节(Byte 简写B) 1Byte=8bit
<h4><strong>二进制存放</strong></h4>
接下来我们看看1个字节都可以存放哪些内容

我们要时刻牢记内存存储的实际上只是0和1，那么就假设我们的计算机只能处理二进制数（二进制计算器？）。看看1个字节可以表示多少个数

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/2_1.jpg"><img style="display: inline;" title="2_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/2_1_thumb.jpg" alt="2_1" width="480" height="84" /></a>

上图，我们把一个字节分成8比特展开，上图表示的二进制数为 00000001，转换为十进制数为1，那么我们用一个字节最多可以表示从00000000—11111111共256个数（十进制从0到255）。
<pre>好，现在我提一个问题，如果我想表示十进制的258怎么办，因为258的二进制数为100000010，我们用一个字节无法完全容纳。</pre>
<pre>我们可能想用计算机表示一个比较大的数，比如十进制数1340054788（2009年1月我国人口数） ，如果用二进制数表示是</pre>
<pre>0100 1111 1101 1111 1001 1101 0000 0100</pre>
<pre><a href="http://www.basilwang.net/wp-content/uploads/2011/09/3_1.jpg"><img style="display: inline;" title="3_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/3_1_thumb.jpg" alt="3_1" width="480" height="154" /></a></pre>
可以看到我们需要4个字节来表示，可是计算机怎么知道它的这四个字节是表示1个数（13亿）还是4个数（1个字节1个数）亦或是3个数？ 所以这里引出了数据类型的概念。
<h4><strong>数据类型和编码</strong></h4>
上节计算机无法确定具体的表示内容的原因是我们对不同大小内容的存放没有确切的限制，类比前面的格子，有的内容用一个格子，有的内容用两个格子，还有的用四个格子。所以必须对内容的存放做限制，比如不管多大的数统一用4个字节存放（实际上就是32位window系统整形int的长度）

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/4_1.jpg"><img style="display: inline;" title="4_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/4_1_thumb.jpg" alt="4_1" width="480" height="130" /></a>

上图是十进制的1

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/5_1.jpg"><img style="display: inline;" title="5_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/5_1_thumb.jpg" alt="5_1" width="480" height="124" /></a>

上图是十进制的4294967296 (4.2亿)

也就是说我们可以表示0~4.2亿的数，虽然这样对于小的数有空间浪费（比如十进制的1，浪费了3个字节）、对更大的数无法表示（比如5.6亿，会溢出），但是我们界定了内容的宽度，使得存储变得简单。

我们常用的整形，就是用四个字节表示，由此我们已可以推断它的取值范围（0~4.2亿，我们这里没有讨论负数，有所简化，但原理一样）。

也就是说，当我们写 int a=3; 实际上在内存中占据了4个字节，如下图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/6_1.jpg"><img style="display: inline;" title="6_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/6_1_thumb.jpg" alt="6_1" width="480" height="130" /></a>

那么字符是怎么显示的呢

先来看一下英文字母及标点符号的表示。由于内存只能表示0、1，我们不得不采用一些办法才能存储字符。我们通常采用字符集(Character Set)的方式，即在计算机中存储时也要使用二进制数来表示，但具体用哪些二进制数字表示哪个符号，当然每个人都可以约定自己的一套（这就叫字符集，注意和编码不同）。

比如十进制的65 代表A

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/7_1.jpg"><img style="display: inline;" title="7_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/7_1_thumb.jpg" alt="7_1" width="480" height="86" /></a>

那么字符码就有26个小写字母、26个大写字母、10个数字、32个符号、33个句柄和一个空格，另外加上一些扩展字符，总共是256个字符码。同整数一样，我们也需要对字符所占的宽度进行约束（要不同样无法辨别），我们可以根据公式

Y=Log2 X Y即为所占宽度，所以256字符需要每个字符占1个字节的宽度，这也就是为什么一个字符占据一个字节的原因。

比如 char a=’3’;

char b=’A’;

这也就是我们常说的ASCII字符集（Single-Byte Character Set,简称SBCS），类似的SBCS还有阿拉伯语ISO8859-6 等等。

至于简体中文、繁体中文、日文和韩文，显然用1个字节存储是不够的，所以采用了双字节字符集的形式(Double-Byte Character Set,简称DBCS)，属于DBCS的有简体中文的GB2312，

繁体中文的BIG5。

标准化协会还另外采用了2个字节的宽度来表示所有的字符的字符集形式即Unicode（宽字节字符集），旨在把全世界的文字用一种字符集(Character Set)表示。目前已经定义了包含英文（一个英文字母也占两个字节）、中文、日文、阿拉伯字母等大约35000个代码点，而实际上2个字节的宽度可以表示65536个代码点。
<h4><strong>变量和指针</strong></h4>
我们了解了数据类型，来看一看变量的声明和使用，以整形为例

int n;

则会在内存中的某一个位置选取4个字节存放该整形，然后计算机记录下该内存的地址（那么内存的地址如何表示？），由于声明并没有赋值，所以只是分配了内存空间并没有赋初值。

这种方式分配空间和动态分配空间(C里用malloc，C++用new)是不同的，静态方式会在该变量n超过其变量作用范围时自动释放（回收），而动态方式需要我们用(C利用free,C++用delete)回收。

如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/8_1.jpg"><img style="display: inline;" title="8_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/8_1_thumb.jpg" alt="8_1" width="480" height="138" /></a>

这里n可以看作是别名，我们的编译器在编译程序的时候做了一些手脚，把n和该段内存的地址建立了关联，这样后面我们可以利用n来方便的更改该段内存的内容，而实际上计算机内部处理还是按照地址去访问的。比如

n=30;

现在来了解一下地址（实际上也是我们在线性排序中提到的格子的编号），因为该编号最终也是会以二进制的形式存储，所以我们也给它规定了一个数据类型，并且限定了它的宽度，这就是指针类型，宽度为4个字节也就是常说的32位（在32位windows系统，比如xp）。

那么当我们一个格子代表一个字节而给它们进行地址编号（也就是指针）的话，最多可以表示2的32次方 4294967296个字节，实际上就是4GB。这也说明32windows系统的寻址空间最多就是4GB,window xp 最大支持的物理内存是4GB。那么如下代码

int *p;

是否像整形变量n一样需要在内存分配空间？分配多大的空间呢？它里面又存放什么内容呢？

要回答上面的问题，我们首先来看一下指针的声明

int *p;

char *x;

double *y;

上面分别声明了指向int的指针、指向char的指针、指向double的指针，它们没有本质的不同，都是占4个字节，在计算机内部处理方式是完全一样的，不同的只是编译器在编译时要检查指向int的指针必须指向int（有点啰嗦）,而不能其他 。所以应该把指针理解成一个二进制数（0到4.2亿）。

再看指针的存储

int *p 声明了这样一个指针，并且像整形一样在内存里分配了四个字节的空间

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/9_1.jpg"><img style="display: inline;" title="9_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/9_1_thumb.jpg" alt="9_1" width="480" height="128" /></a>

只不过这个指针变量没有任何内容，换句话说，没有指向任何的int变量。

int n=3;

int *p;

p=&#38;n;

其中&#38;是取地址操作符，意思是取变量n在内存中的地址并且放到p分配的空间存放，假设是十进制的2293532，那么二进制是0000 0000 0010 0010 1111 1111 0001 1100，则p中存放的值如下图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/10_1.jpg"><img style="display: inline;" title="10_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/10_1_thumb.jpg" alt="10_1" width="480" height="150" /></a>

提到&#38;就不能不提* ，*是解引用操作符，那么什么时候用*呢，看一看前面定义的指针p，它里面存放的是n变量的地址，可是我们对这个二进制数不感兴趣，很多时候我们需要了解p的值（某地址）究竟存放什么样的内容？这时候就用到了*

cout &#60;&#60;*p&#60;&#60;endl;

上一句是根据地址十进制的2293532（即n对应的地址）去找里面的内容，为3。因此我们可以把p看作一个指向n的指针（指针是抽象的，实际使用地址表示，如下图）

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/11_1.jpg"><img style="display: inline;" title="11_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/11_1_thumb.jpg" alt="11_1" width="480" height="270" /></a>

如果有 int k=*p;

则会给k分配一个4个字节的空间，然后把p的内容解引用（实际上是依据p存储的内容即地址去找该地址里的内容，形象的称p指针所指向的内容）存储到k对应的空间中。

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/12_1.jpg"><img style="display: inline;" title="12_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/12_1_thumb.jpg" alt="12_1" width="480" height="268" /></a>

我们同样可以更改p的指向

比如int s=5;

P=&#38;s;

如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/13_1.jpg"><img style="display: inline;" title="13_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/13_1_thumb.jpg" alt="13_1" width="480" height="358" /></a>
<h4><strong>引用</strong></h4>
引用有时候又称为别名，它可以用作对象的另一个名字。通过引用我们可以间接地操纵对象，使用方式类似于指针（引用在内部存放的是一个地址，这点上和指针是类似的），但是不需要指针的语法。在实际的程序中，引用主要被用作函数的形式参数或者返回值。

我们看一下引用的声明

int i=5;

int &#38;j=I;

j=7

cout&#60;&#60;i&#60;&#60;endl;

j+=2;

cout&#60;&#60;i&#60;&#60;endl;

int *pi=&#38;j;

cout &#60;&#60;pi&#60;&#60;endl; //打印的是i的地址

引用的所有操作实际上都是应用在它所指的对象身上，包括取地址操作符

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/14_1.jpg"><img style="display: inline;" title="14_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/14_1_thumb.jpg" alt="14_1" width="480" height="348" /></a>

如图对引用j的所有操作都作用到变量i上，使得引用j就像透明的或者不存在一样，像极了周星驰电影《大内密探零零发》中无相神王的隔山打牛重拳，“中拳者无事，旁观者毙命！”
<h4>数组</h4>
来看一下数组的声明

int ia[3];

此语句会在内存中分配12个字节的空间准备存放三个int

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/15_1.jpg"><img style="display: inline;" title="15_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/15_1_thumb.jpg" alt="15_1" width="480" height="372" /></a>

那么我们能不能得到数组元素的地址或者使用指针来操作数组元素呢，答案是肯定的。

如果只简单写ia; 即只写数组名则代表数组中第一个元素的地址，它的类型是数组元素类型的指针,本例是int *;

因此ia和&#38;ia[0]是等价的，都是数组第一个元素的地址

int *p=&#38;ia[0];

表示p里面存放的是数组第一个元素的地址

cout&#60;&#60;*p&#60;&#60;endl; //使用了解引用，参考整形指针解引用的处理方式，打印数组第一个元素的内容。

同理 ia+1和 &#38;ia[1] 取到的是数组第二个元素的地址（注意ia+1中的1是增加了一个数据类型的宽度，int是4个字节）

ia[1]和*(ia+1) 一致，打印的是第二个元素的内容。

此种数组的声明方式会在离开数组变量作用域时自动释放，不会造成内存泄漏。
<h4><strong>动态存储分配</strong></h4>
new 该运算符返回一个指向所分配空间的指针。例如，要为一个整数动态分配存储空间，可以用下面的语句说明一个整形指针变量；

int *y;

y=new int;

*y=10;

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/16_1.jpg"><img style="display: inline;" title="16_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/16_1_thumb.jpg" alt="16_1" width="480" height="282" /></a>

为了在运行时创建一个可动态变化的一维整形数组x,可先将x声明为一个整形的指针，然后

用new为数组动态的分配存储空间。比如

int *x;

x=new int[3];

随后可以用x[0],x[1]等方式来访问每个数组元素，用下标方式访问数组元素很像静态的数组声明，比如

int x1[3];

我们可以用x1[0],x1[1]的方式来访问每个数组元素。可能同学们比较熟悉静态数组的声明访问方式，现在就需要了解动态分配存储空间的数组方式。两者有两方面的不同

1） 声明时，动态方式是声明了一个指针类型，静态数组是声明一个数组类型。但两者访问方式完全一样，较多采用x[0],x[1]等方式

2） 静态方式会在离开数组变量作用域时自动释放，而动态方式我们需要通过delete []x手动释放。
<h4><strong>函数参数传递在内存中的表示</strong></h4>
参数传递有两种方式:一种是按值传递, 在这种参数传递方式下,把实参的值复制到函数局部工作区相应的副本中,函数使用副本执行必要的计算。因此函数实际修改的是副本的值，实参的值不变。

按值传递有分两种：1将变量名作为形参和实参 2传递变量指针

void swap(int a,int b)

{//形参为整型变量

int temp=a;

a=b;

b=temp;

}

int main()

{

int i=3,j=4;

swap(i，j);

cout&#60;&#60;"i="&#60;&#60;i&#60;&#60;",j="&#60;&#60;j&#60;&#60;endl;

}

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/17_1.jpg"><img style="display: inline;" title="17_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/17_1_thumb.jpg" alt="17_1" width="480" height="240" /></a>

void swap(int *a,int *b)

{//形参为整型变量

int temp;

temp=*a;

*a=*b;

*b=temp;

}

int main()

{

int i=3,j=4;

swap(&#38;I,&#38;j);

cout&#60;&#60;"i="&#60;&#60;i&#60;&#60;",j="&#60;&#60;j&#60;&#60;endl;

}

当执行到函数体temp=*a; 内存存储如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/18_1.jpg"><img style="display: inline;" title="18_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/18_1_thumb.jpg" alt="18_1" width="480" height="228" /></a>

当执行到函数体*a=*b; 内存存储如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/19_1.jpg"><img style="display: inline;" title="19_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/19_1_thumb.jpg" alt="19_1" width="480" height="226" /></a>

当执行到函数体*b=temp; 内存存储如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/20_1.jpg"><img style="display: inline;" title="20_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/20_1_thumb.jpg" alt="20_1" width="480" height="234" /></a>

第二种方式是按引用传递参数。在这种参数传递方式下，需将形参声明为引用类型，即在参数名前加上符号”&#38;”。当一个实参与一个引用类型结合时，被传递的不是实参的值，而是实参的地址。

void swap(int &#38;a,int &#38;b)

{//形参为整型变量

int temp;

temp=a;

a=b;

b=temp;

}

int main()

{

int i=3,j=4;

swap(i,j);

cout&#60;&#60;"i="&#60;&#60;i&#60;&#60;",j="&#60;&#60;j&#60;&#60;endl;

}

当执行函数体内temp=a; 内存存储如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/21_1.jpg"><img style="display: inline;" title="21_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/21_1_thumb.jpg" alt="21_1" width="480" height="226" /></a>

当执行函数体内a=b;内存存储如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/22_1.jpg"><img style="display: inline;" title="22_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/22_1_thumb.jpg" alt="22_1" width="480" height="234" /></a>

当执行函数体内b=temp;内存存储如图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/23_1.jpg"><img style="display: inline;" title="23_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/23_1_thumb.jpg" alt="23_1" width="480" height="246" /></a>

函数的返回值同样遵循这样的两种方式（按值返回或者按引用返回），只要我们牢牢把握内存分配的实质，处理类似的问题会得心应手。
<h3><strong>参考文献</strong></h3>
1. C++ Primer 中文版   Stanley B.Lippman等著  潘爱民等译 中国电力出版社

2. C++ 大学教程 Harvey M.Deitel等著 邱仲潘等译 电子工业出版社

3. 数据结构（C++语言版） 王晓东著 科学出版社

4. Programming Windows(Fifth Edition)影印版 Charles Petzold  人民邮电出版社

5. Windows核心编程（第四版） Jeffery Richter著  机械工业出版社]]></description>
			<content:encoded><![CDATA[<p>—概述</p>
<p>—线性排序</p>
<p>—二进制存放</p>
<p>—数据类型和编码</p>
<p>—变量和指针</p>
<p>—引用</p>
<p>—数组</p>
<p>—动态存储分配</p>
<p>—函数参数传递在内存中的表示</p>
<h3><strong>概述</strong></h3>
<p>c++的学习中，对指针的理解和把握相当重要，可能很多同学对此感到困惑。我个人感觉指针的理解实际上还是依赖于对内存存储的理解，因此了解内存的存储机制就显得至关重要。</p>
<p>当然由于内存的存储机制实际上比较复杂，而且我们的任务是学习程序的编写，所以我这里更多是从程序的角度来看内存的存储（有一定程度的简化）。但当我们了解了内存存储的方式，知道程序中的常量、变量、指针在内存中的表示，又能够进一步指导我们程序的书写。</p>
<h4>线性排序</h4>
<p>首先请把内存想象成一段连续的格子，每个格子可以存储内容（如果一个格子装不下，可能放到多个格子中，这种情况很普遍）</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/1_1.jpg"><img style="display: inline;" title="1_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/1_1_thumb.jpg" alt="1_1" width="480" height="90" /></a></p>
<p>注意两点</p>
<p>1 格子是有序排列的，也就是每个格子都有编号，从小到大排列。我们也常说内存是线性空间排列的（就是想象成一条线）</p>
<p>2. 每个格子大小是1个字节(Byte 简写B) 1Byte=8bit</p>
<h4><strong>二进制存放</strong></h4>
<p>接下来我们看看1个字节都可以存放哪些内容</p>
<p>我们要时刻牢记内存存储的实际上只是0和1，那么就假设我们的计算机只能处理二进制数（二进制计算器？）。看看1个字节可以表示多少个数</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/2_1.jpg"><img style="display: inline;" title="2_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/2_1_thumb.jpg" alt="2_1" width="480" height="84" /></a></p>
<p>上图，我们把一个字节分成8比特展开，上图表示的二进制数为 00000001，转换为十进制数为1，那么我们用一个字节最多可以表示从00000000—11111111共256个数（十进制从0到255）。</p>
<pre>好，现在我提一个问题，如果我想表示十进制的258怎么办，因为258的二进制数为100000010，我们用一个字节无法完全容纳。</pre>
<pre>我们可能想用计算机表示一个比较大的数，比如十进制数1340054788（2009年1月我国人口数） ，如果用二进制数表示是</pre>
<pre>0100 1111 1101 1111 1001 1101 0000 0100</pre>
<pre><a href="http://www.basilwang.net/wp-content/uploads/2011/09/3_1.jpg"><img style="display: inline;" title="3_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/3_1_thumb.jpg" alt="3_1" width="480" height="154" /></a></pre>
<p>可以看到我们需要4个字节来表示，可是计算机怎么知道它的这四个字节是表示1个数（13亿）还是4个数（1个字节1个数）亦或是3个数？ 所以这里引出了数据类型的概念。</p>
<h4><strong>数据类型和编码</strong></h4>
<p>上节计算机无法确定具体的表示内容的原因是我们对不同大小内容的存放没有确切的限制，类比前面的格子，有的内容用一个格子，有的内容用两个格子，还有的用四个格子。所以必须对内容的存放做限制，比如不管多大的数统一用4个字节存放（实际上就是32位window系统整形int的长度）</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/4_1.jpg"><img style="display: inline;" title="4_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/4_1_thumb.jpg" alt="4_1" width="480" height="130" /></a></p>
<p>上图是十进制的1</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/5_1.jpg"><img style="display: inline;" title="5_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/5_1_thumb.jpg" alt="5_1" width="480" height="124" /></a></p>
<p>上图是十进制的4294967296 (4.2亿)</p>
<p>也就是说我们可以表示0~4.2亿的数，虽然这样对于小的数有空间浪费（比如十进制的1，浪费了3个字节）、对更大的数无法表示（比如5.6亿，会溢出），但是我们界定了内容的宽度，使得存储变得简单。</p>
<p>我们常用的整形，就是用四个字节表示，由此我们已可以推断它的取值范围（0~4.2亿，我们这里没有讨论负数，有所简化，但原理一样）。</p>
<p>也就是说，当我们写 int a=3; 实际上在内存中占据了4个字节，如下图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/6_1.jpg"><img style="display: inline;" title="6_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/6_1_thumb.jpg" alt="6_1" width="480" height="130" /></a></p>
<p>那么字符是怎么显示的呢</p>
<p>先来看一下英文字母及标点符号的表示。由于内存只能表示0、1，我们不得不采用一些办法才能存储字符。我们通常采用字符集(Character Set)的方式，即在计算机中存储时也要使用二进制数来表示，但具体用哪些二进制数字表示哪个符号，当然每个人都可以约定自己的一套（这就叫字符集，注意和编码不同）。</p>
<p>比如十进制的65 代表A</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/7_1.jpg"><img style="display: inline;" title="7_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/7_1_thumb.jpg" alt="7_1" width="480" height="86" /></a></p>
<p>那么字符码就有26个小写字母、26个大写字母、10个数字、32个符号、33个句柄和一个空格，另外加上一些扩展字符，总共是256个字符码。同整数一样，我们也需要对字符所占的宽度进行约束（要不同样无法辨别），我们可以根据公式</p>
<p>Y=Log2 X Y即为所占宽度，所以256字符需要每个字符占1个字节的宽度，这也就是为什么一个字符占据一个字节的原因。</p>
<p>比如 char a=’3’;</p>
<p>char b=’A’;</p>
<p>这也就是我们常说的ASCII字符集（Single-Byte Character Set,简称SBCS），类似的SBCS还有阿拉伯语ISO8859-6 等等。</p>
<p>至于简体中文、繁体中文、日文和韩文，显然用1个字节存储是不够的，所以采用了双字节字符集的形式(Double-Byte Character Set,简称DBCS)，属于DBCS的有简体中文的GB2312，</p>
<p>繁体中文的BIG5。</p>
<p>标准化协会还另外采用了2个字节的宽度来表示所有的字符的字符集形式即Unicode（宽字节字符集），旨在把全世界的文字用一种字符集(Character Set)表示。目前已经定义了包含英文（一个英文字母也占两个字节）、中文、日文、阿拉伯字母等大约35000个代码点，而实际上2个字节的宽度可以表示65536个代码点。</p>
<h4><strong>变量和指针</strong></h4>
<p>我们了解了数据类型，来看一看变量的声明和使用，以整形为例</p>
<p>int n;</p>
<p>则会在内存中的某一个位置选取4个字节存放该整形，然后计算机记录下该内存的地址（那么内存的地址如何表示？），由于声明并没有赋值，所以只是分配了内存空间并没有赋初值。</p>
<p>这种方式分配空间和动态分配空间(C里用malloc，C++用new)是不同的，静态方式会在该变量n超过其变量作用范围时自动释放（回收），而动态方式需要我们用(C利用free,C++用delete)回收。</p>
<p>如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/8_1.jpg"><img style="display: inline;" title="8_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/8_1_thumb.jpg" alt="8_1" width="480" height="138" /></a></p>
<p>这里n可以看作是别名，我们的编译器在编译程序的时候做了一些手脚，把n和该段内存的地址建立了关联，这样后面我们可以利用n来方便的更改该段内存的内容，而实际上计算机内部处理还是按照地址去访问的。比如</p>
<p>n=30;</p>
<p>现在来了解一下地址（实际上也是我们在线性排序中提到的格子的编号），因为该编号最终也是会以二进制的形式存储，所以我们也给它规定了一个数据类型，并且限定了它的宽度，这就是指针类型，宽度为4个字节也就是常说的32位（在32位windows系统，比如xp）。</p>
<p>那么当我们一个格子代表一个字节而给它们进行地址编号（也就是指针）的话，最多可以表示2的32次方 4294967296个字节，实际上就是4GB。这也说明32windows系统的寻址空间最多就是4GB,window xp 最大支持的物理内存是4GB。那么如下代码</p>
<p>int *p;</p>
<p>是否像整形变量n一样需要在内存分配空间？分配多大的空间呢？它里面又存放什么内容呢？</p>
<p>要回答上面的问题，我们首先来看一下指针的声明</p>
<p>int *p;</p>
<p>char *x;</p>
<p>double *y;</p>
<p>上面分别声明了指向int的指针、指向char的指针、指向double的指针，它们没有本质的不同，都是占4个字节，在计算机内部处理方式是完全一样的，不同的只是编译器在编译时要检查指向int的指针必须指向int（有点啰嗦）,而不能其他 。所以应该把指针理解成一个二进制数（0到4.2亿）。</p>
<p>再看指针的存储</p>
<p>int *p 声明了这样一个指针，并且像整形一样在内存里分配了四个字节的空间</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/9_1.jpg"><img style="display: inline;" title="9_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/9_1_thumb.jpg" alt="9_1" width="480" height="128" /></a></p>
<p>只不过这个指针变量没有任何内容，换句话说，没有指向任何的int变量。</p>
<p>int n=3;</p>
<p>int *p;</p>
<p>p=&amp;n;</p>
<p>其中&amp;是取地址操作符，意思是取变量n在内存中的地址并且放到p分配的空间存放，假设是十进制的2293532，那么二进制是0000 0000 0010 0010 1111 1111 0001 1100，则p中存放的值如下图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/10_1.jpg"><img style="display: inline;" title="10_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/10_1_thumb.jpg" alt="10_1" width="480" height="150" /></a></p>
<p>提到&amp;就不能不提* ，*是解引用操作符，那么什么时候用*呢，看一看前面定义的指针p，它里面存放的是n变量的地址，可是我们对这个二进制数不感兴趣，很多时候我们需要了解p的值（某地址）究竟存放什么样的内容？这时候就用到了*</p>
<p>cout &lt;&lt;*p&lt;&lt;endl;</p>
<p>上一句是根据地址十进制的2293532（即n对应的地址）去找里面的内容，为3。因此我们可以把p看作一个指向n的指针（指针是抽象的，实际使用地址表示，如下图）</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/11_1.jpg"><img style="display: inline;" title="11_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/11_1_thumb.jpg" alt="11_1" width="480" height="270" /></a></p>
<p>如果有 int k=*p;</p>
<p>则会给k分配一个4个字节的空间，然后把p的内容解引用（实际上是依据p存储的内容即地址去找该地址里的内容，形象的称p指针所指向的内容）存储到k对应的空间中。</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/12_1.jpg"><img style="display: inline;" title="12_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/12_1_thumb.jpg" alt="12_1" width="480" height="268" /></a></p>
<p>我们同样可以更改p的指向</p>
<p>比如int s=5;</p>
<p>P=&amp;s;</p>
<p>如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/13_1.jpg"><img style="display: inline;" title="13_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/13_1_thumb.jpg" alt="13_1" width="480" height="358" /></a></p>
<h4><strong>引用</strong></h4>
<p>引用有时候又称为别名，它可以用作对象的另一个名字。通过引用我们可以间接地操纵对象，使用方式类似于指针（引用在内部存放的是一个地址，这点上和指针是类似的），但是不需要指针的语法。在实际的程序中，引用主要被用作函数的形式参数或者返回值。</p>
<p>我们看一下引用的声明</p>
<p>int i=5;</p>
<p>int &amp;j=I;</p>
<p>j=7</p>
<p>cout&lt;&lt;i&lt;&lt;endl;</p>
<p>j+=2;</p>
<p>cout&lt;&lt;i&lt;&lt;endl;</p>
<p>int *pi=&amp;j;</p>
<p>cout &lt;&lt;pi&lt;&lt;endl; //打印的是i的地址</p>
<p>引用的所有操作实际上都是应用在它所指的对象身上，包括取地址操作符</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/14_1.jpg"><img style="display: inline;" title="14_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/14_1_thumb.jpg" alt="14_1" width="480" height="348" /></a></p>
<p>如图对引用j的所有操作都作用到变量i上，使得引用j就像透明的或者不存在一样，像极了周星驰电影《大内密探零零发》中无相神王的隔山打牛重拳，“中拳者无事，旁观者毙命！”</p>
<h4>数组</h4>
<p>来看一下数组的声明</p>
<p>int ia[3];</p>
<p>此语句会在内存中分配12个字节的空间准备存放三个int</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/15_1.jpg"><img style="display: inline;" title="15_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/15_1_thumb.jpg" alt="15_1" width="480" height="372" /></a></p>
<p>那么我们能不能得到数组元素的地址或者使用指针来操作数组元素呢，答案是肯定的。</p>
<p>如果只简单写ia; 即只写数组名则代表数组中第一个元素的地址，它的类型是数组元素类型的指针,本例是int *;</p>
<p>因此ia和&amp;ia[0]是等价的，都是数组第一个元素的地址</p>
<p>int *p=&amp;ia[0];</p>
<p>表示p里面存放的是数组第一个元素的地址</p>
<p>cout&lt;&lt;*p&lt;&lt;endl; //使用了解引用，参考整形指针解引用的处理方式，打印数组第一个元素的内容。</p>
<p>同理 ia+1和 &amp;ia[1] 取到的是数组第二个元素的地址（注意ia+1中的1是增加了一个数据类型的宽度，int是4个字节）</p>
<p>ia[1]和*(ia+1) 一致，打印的是第二个元素的内容。</p>
<p>此种数组的声明方式会在离开数组变量作用域时自动释放，不会造成内存泄漏。</p>
<h4><strong>动态存储分配</strong></h4>
<p>new 该运算符返回一个指向所分配空间的指针。例如，要为一个整数动态分配存储空间，可以用下面的语句说明一个整形指针变量；</p>
<p>int *y;</p>
<p>y=new int;</p>
<p>*y=10;</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/16_1.jpg"><img style="display: inline;" title="16_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/16_1_thumb.jpg" alt="16_1" width="480" height="282" /></a></p>
<p>为了在运行时创建一个可动态变化的一维整形数组x,可先将x声明为一个整形的指针，然后</p>
<p>用new为数组动态的分配存储空间。比如</p>
<p>int *x;</p>
<p>x=new int[3];</p>
<p>随后可以用x[0],x[1]等方式来访问每个数组元素，用下标方式访问数组元素很像静态的数组声明，比如</p>
<p>int x1[3];</p>
<p>我们可以用x1[0],x1[1]的方式来访问每个数组元素。可能同学们比较熟悉静态数组的声明访问方式，现在就需要了解动态分配存储空间的数组方式。两者有两方面的不同</p>
<p>1） 声明时，动态方式是声明了一个指针类型，静态数组是声明一个数组类型。但两者访问方式完全一样，较多采用x[0],x[1]等方式</p>
<p>2） 静态方式会在离开数组变量作用域时自动释放，而动态方式我们需要通过delete []x手动释放。</p>
<h4><strong>函数参数传递在内存中的表示</strong></h4>
<p>参数传递有两种方式:一种是按值传递, 在这种参数传递方式下,把实参的值复制到函数局部工作区相应的副本中,函数使用副本执行必要的计算。因此函数实际修改的是副本的值，实参的值不变。</p>
<p>按值传递有分两种：1将变量名作为形参和实参 2传递变量指针</p>
<p>void swap(int a,int b)</p>
<p>{//形参为整型变量</p>
<p>int temp=a;</p>
<p>a=b;</p>
<p>b=temp;</p>
<p>}</p>
<p>int main()</p>
<p>{</p>
<p>int i=3,j=4;</p>
<p>swap(i，j);</p>
<p>cout&lt;&lt;&#8221;i=&#8221;&lt;&lt;i&lt;&lt;&#8221;,j=&#8221;&lt;&lt;j&lt;&lt;endl;</p>
<p>}</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/17_1.jpg"><img style="display: inline;" title="17_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/17_1_thumb.jpg" alt="17_1" width="480" height="240" /></a></p>
<p>void swap(int *a,int *b)</p>
<p>{//形参为整型变量</p>
<p>int temp;</p>
<p>temp=*a;</p>
<p>*a=*b;</p>
<p>*b=temp;</p>
<p>}</p>
<p>int main()</p>
<p>{</p>
<p>int i=3,j=4;</p>
<p>swap(&amp;I,&amp;j);</p>
<p>cout&lt;&lt;&#8221;i=&#8221;&lt;&lt;i&lt;&lt;&#8221;,j=&#8221;&lt;&lt;j&lt;&lt;endl;</p>
<p>}</p>
<p>当执行到函数体temp=*a; 内存存储如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/18_1.jpg"><img style="display: inline;" title="18_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/18_1_thumb.jpg" alt="18_1" width="480" height="228" /></a></p>
<p>当执行到函数体*a=*b; 内存存储如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/19_1.jpg"><img style="display: inline;" title="19_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/19_1_thumb.jpg" alt="19_1" width="480" height="226" /></a></p>
<p>当执行到函数体*b=temp; 内存存储如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/20_1.jpg"><img style="display: inline;" title="20_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/20_1_thumb.jpg" alt="20_1" width="480" height="234" /></a></p>
<p>第二种方式是按引用传递参数。在这种参数传递方式下，需将形参声明为引用类型，即在参数名前加上符号”&amp;”。当一个实参与一个引用类型结合时，被传递的不是实参的值，而是实参的地址。</p>
<p>void swap(int &amp;a,int &amp;b)</p>
<p>{//形参为整型变量</p>
<p>int temp;</p>
<p>temp=a;</p>
<p>a=b;</p>
<p>b=temp;</p>
<p>}</p>
<p>int main()</p>
<p>{</p>
<p>int i=3,j=4;</p>
<p>swap(i,j);</p>
<p>cout&lt;&lt;&#8221;i=&#8221;&lt;&lt;i&lt;&lt;&#8221;,j=&#8221;&lt;&lt;j&lt;&lt;endl;</p>
<p>}</p>
<p>当执行函数体内temp=a; 内存存储如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/21_1.jpg"><img style="display: inline;" title="21_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/21_1_thumb.jpg" alt="21_1" width="480" height="226" /></a></p>
<p>当执行函数体内a=b;内存存储如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/22_1.jpg"><img style="display: inline;" title="22_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/22_1_thumb.jpg" alt="22_1" width="480" height="234" /></a></p>
<p>当执行函数体内b=temp;内存存储如图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/23_1.jpg"><img style="display: inline;" title="23_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/23_1_thumb.jpg" alt="23_1" width="480" height="246" /></a></p>
<p>函数的返回值同样遵循这样的两种方式（按值返回或者按引用返回），只要我们牢牢把握内存分配的实质，处理类似的问题会得心应手。</p>
<h3><strong>参考文献</strong></h3>
<p>1. C++ Primer 中文版   Stanley B.Lippman等著  潘爱民等译 中国电力出版社</p>
<p>2. C++ 大学教程 Harvey M.Deitel等著 邱仲潘等译 电子工业出版社</p>
<p>3. 数据结构（C++语言版） 王晓东著 科学出版社</p>
<p>4. Programming Windows(Fifth Edition)影印版 Charles Petzold  人民邮电出版社</p>
<p>5. Windows核心编程（第四版） Jeffery Richter著  机械工业出版社</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2010/09/cplusplus-pointer-storage-structure/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>重构一个贪吃蛇游戏（linux c++)</title>
		<link>http://www.basilwang.net/2010/08/refactor-greedy-snake-cplusplus/</link>
		<comments>http://www.basilwang.net/2010/08/refactor-greedy-snake-cplusplus/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 03:11:00 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[c++]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2010/08/%e9%87%8d%e6%9e%84%e4%b8%80%e4%b8%aa%e8%b4%aa%e5%90%83%e8%9b%87%e6%b8%b8%e6%88%8f%ef%bc%88linux-c/</guid>
		<description><![CDATA[最近读<a href="http://www.cnblogs.com/dave_cn">dave_cn</a>的<a href="http://www.cnblogs.com/dave_cn/archive/2010/07/18/1780317.html">[原创]分享自己写的一个贪吃蛇的游戏(Linux)</a> ，C程序写的，就想着用C++重写一下，把面向对象的思想也引入进来。

这里感谢dave_cn，重构后应该有40%的代码是重用的，省了不少功夫。

程序继续采用了ncurses.h库，关于ncurses<a href="http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/">猛击这里</a>。不知道在window下有没有类似的库（查了一下，可以用conio.h在类dos窗口下实现，有空实现一个window版)。

第一次在linux下用c++写东西，碰到的问题比较多，好歹都解决了，这里也一并做记号。

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/snake_thumb.jpg"><img style="display: inline;" title="snake_thumb" src="http://www.basilwang.net/wp-content/uploads/2011/09/snake_thumb_thumb.jpg" alt="snake_thumb" width="480" height="409" /></a>

需求比较简单，直接上UML图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/uml_thumb_1.jpg"><img style="display: inline;" title="uml_thumb_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/uml_thumb_1_thumb.jpg" alt="uml_thumb_1" width="480" height="733" /></a>

Screen 类 主要负责定时刷新
Snake类    footprintx,footprinty  由于蛇移动实际就是重绘窗口，所以需要把它走过的痕迹擦掉（用空字符代替*即可),只记录一步痕迹
list  蛇的身体，采用了双链表，关于双链表<a href="http://baike.baidu.com/view/1627720.htm">猛击这里</a>，代码中调用 dlinkedList.h
bodyReshape()  每一步移动时，其实就是蛇身体各部位坐标的移动，bodyReshape修改各部位坐标
eraseFootPrint() 擦除痕迹
isClapseArea() 是否走到边界
isSpiralDead() 是否头部碰到身体
lifeProbing()  生命迹象探测，就是看看是不是还活着
move()   移动，在移动的过程会做一些工作，详见时序图
receivingNavi() 接受键盘控制蛇头移动方向
selfGeneration() 吃到Block后，身体张长
LivingArea类 蛇的活动区域
Block 障碍物，由于一次只有一个障碍，所以LivingArea和Block是1对1的
blockChecking() 检测障碍物
isEattingPhase() 是否是吃Block的时刻，当蛇头和Block的坐标相同，即认为是isEattingPhase=true
isDigestPhase() 未用
eraseBlock() 将isBlockExisted置为false
generateBlock() 生成Block
再看一下时序图

<a href="http://www.basilwang.net/wp-content/uploads/2011/09/sequence_thumb.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="sequence_thumb" src="http://www.basilwang.net/wp-content/uploads/2011/09/sequence_thumb_thumb.jpg" border="0" alt="sequence_thumb" width="484" height="815" /></a>

关于蛇的身体，原c程序采用的是一个倒置的首尾相连的链表,head-&#62;front指向snake的尾部
如: [a]&#60;-[b]&#60;-[c]&#60;-[d]    a为head
&#124;                     ^     snake移动的时候,只用head指向d,
`-------------- '     并且修改d的(y,x)为snake头移动到的位置.
这样的好处是在移动时（身体不增长时），只需要把不用的节点（即上面提到的痕迹）设为头节点，修改其坐标为头的坐标

重构的时候为了简单，用了双链表的源代码，简单的删除痕迹节点，增加新节点，效率不高，简单粗暴。

原c代码
<pre class="code"><span style="color: blue;">void </span>movesnake(<span style="color: blue;">struct </span><span style="color: #2b91af;">TSnake </span>*psnake)
{
 <span style="color: blue;">int </span>hy = psnake-&#62;head-&#62;y;
 <span style="color: blue;">int </span>hx = psnake-&#62;head-&#62;x;

 psnake-&#62;head = GetSnakeTail(psnake);

 <span style="color: blue;">switch </span>(psnake-&#62;dir) {
 <span style="color: blue;">case </span>DIR_UP:
     psnake-&#62;head-&#62;y = hy - 1;
     psnake-&#62;head-&#62;x = hx;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">case </span>DIR_DOWN:
     psnake-&#62;head-&#62;y = hy + 1;
     psnake-&#62;head-&#62;x = hx;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">case </span>DIR_LEFT:
     psnake-&#62;head-&#62;y = hy;
     psnake-&#62;head-&#62;x = hx - 1;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">case </span>DIR_RIGHT:
     psnake-&#62;head-&#62;y = hy;
     psnake-&#62;head-&#62;x = hx + 1;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">default</span>:
     <span style="color: blue;">break</span>;
 }
}</pre>
重构后c++代码
<pre class="code"><span style="color: blue;">void </span>Snake::bodyReshape()
{
  SnakeNode t;
  list.pop_back(t);
  footprinty=t.y;
  footprintx=t.x;
  list.retrieve(0,t);
  <span style="color: blue;">switch </span>(dir)
  {
   <span style="color: blue;">case </span>DIR_UP:
     t.y = t.y - 1;
     t.x = t.x;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">case </span>DIR_DOWN:
     t.y = t.y + 1;
     t.x = t.x;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">case </span>DIR_LEFT:
     t.y = t.y;
     t.x = t.x - 1;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">case </span>DIR_RIGHT:
     t.y = t.y;
     t.x = t.x + 1;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">default</span>:
     <span style="color: blue;">break</span>;
  }
  list.insert(0,t);

}</pre>
编译：

sudo g++ -o mySnake mySnake.cpp Screen.cpp LivingArea.cpp Snake.cpp SnakeNode.cpp Block.cpp –lncurses

<a href="http://files.cnblogs.com/basilwang/mysnake_v2.rar">源代码下载</a>]]></description>
			<content:encoded><![CDATA[<p>最近读<a href="http://www.cnblogs.com/dave_cn">dave_cn</a>的<a href="http://www.cnblogs.com/dave_cn/archive/2010/07/18/1780317.html">[原创]分享自己写的一个贪吃蛇的游戏(Linux)</a> ，C程序写的，就想着用C++重写一下，把面向对象的思想也引入进来。</p>
<p>这里感谢dave_cn，重构后应该有40%的代码是重用的，省了不少功夫。</p>
<p>程序继续采用了ncurses.h库，关于ncurses<a href="http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/">猛击这里</a>。不知道在window下有没有类似的库（查了一下，可以用conio.h在类dos窗口下实现，有空实现一个window版)。</p>
<p>第一次在linux下用c++写东西，碰到的问题比较多，好歹都解决了，这里也一并做记号。</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/snake_thumb.jpg"><img style="display: inline;" title="snake_thumb" src="http://www.basilwang.net/wp-content/uploads/2011/09/snake_thumb_thumb.jpg" alt="snake_thumb" width="480" height="409" /></a></p>
<p>需求比较简单，直接上UML图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/uml_thumb_1.jpg"><img style="display: inline;" title="uml_thumb_1" src="http://www.basilwang.net/wp-content/uploads/2011/09/uml_thumb_1_thumb.jpg" alt="uml_thumb_1" width="480" height="733" /></a></p>
<p>Screen 类 主要负责定时刷新<br />
Snake类    footprintx,footprinty  由于蛇移动实际就是重绘窗口，所以需要把它走过的痕迹擦掉（用空字符代替*即可),只记录一步痕迹<br />
list  蛇的身体，采用了双链表，关于双链表<a href="http://baike.baidu.com/view/1627720.htm">猛击这里</a>，代码中调用 dlinkedList.h<br />
bodyReshape()  每一步移动时，其实就是蛇身体各部位坐标的移动，bodyReshape修改各部位坐标<br />
eraseFootPrint() 擦除痕迹<br />
isClapseArea() 是否走到边界<br />
isSpiralDead() 是否头部碰到身体<br />
lifeProbing()  生命迹象探测，就是看看是不是还活着<br />
move()   移动，在移动的过程会做一些工作，详见时序图<br />
receivingNavi() 接受键盘控制蛇头移动方向<br />
selfGeneration() 吃到Block后，身体张长<br />
LivingArea类 蛇的活动区域<br />
Block 障碍物，由于一次只有一个障碍，所以LivingArea和Block是1对1的<br />
blockChecking() 检测障碍物<br />
isEattingPhase() 是否是吃Block的时刻，当蛇头和Block的坐标相同，即认为是isEattingPhase=true<br />
isDigestPhase() 未用<br />
eraseBlock() 将isBlockExisted置为false<br />
generateBlock() 生成Block<br />
再看一下时序图</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/sequence_thumb.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="sequence_thumb" src="http://www.basilwang.net/wp-content/uploads/2011/09/sequence_thumb_thumb.jpg" border="0" alt="sequence_thumb" width="484" height="815" /></a></p>
<p>关于蛇的身体，原c程序采用的是一个倒置的首尾相连的链表,head-&gt;front指向snake的尾部<br />
如: [a]&lt;-[b]&lt;-[c]&lt;-[d]    a为head<br />
|                     ^     snake移动的时候,只用head指向d,<br />
`&#8212;&#8212;&#8212;&#8212;&#8211; &#8216;     并且修改d的(y,x)为snake头移动到的位置.<br />
这样的好处是在移动时（身体不增长时），只需要把不用的节点（即上面提到的痕迹）设为头节点，修改其坐标为头的坐标</p>
<p>重构的时候为了简单，用了双链表的源代码，简单的删除痕迹节点，增加新节点，效率不高，简单粗暴。</p>
<p>原c代码</p>
<pre class="code"><span style="color: blue;">void </span>movesnake(<span style="color: blue;">struct </span><span style="color: #2b91af;">TSnake </span>*psnake)
{
 <span style="color: blue;">int </span>hy = psnake-&gt;head-&gt;y;
 <span style="color: blue;">int </span>hx = psnake-&gt;head-&gt;x;

 psnake-&gt;head = GetSnakeTail(psnake);

 <span style="color: blue;">switch </span>(psnake-&gt;dir) {
 <span style="color: blue;">case </span>DIR_UP:
     psnake-&gt;head-&gt;y = hy - 1;
     psnake-&gt;head-&gt;x = hx;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">case </span>DIR_DOWN:
     psnake-&gt;head-&gt;y = hy + 1;
     psnake-&gt;head-&gt;x = hx;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">case </span>DIR_LEFT:
     psnake-&gt;head-&gt;y = hy;
     psnake-&gt;head-&gt;x = hx - 1;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">case </span>DIR_RIGHT:
     psnake-&gt;head-&gt;y = hy;
     psnake-&gt;head-&gt;x = hx + 1;
     <span style="color: blue;">break</span>;

 <span style="color: blue;">default</span>:
     <span style="color: blue;">break</span>;
 }
}</pre>
<p>重构后c++代码</p>
<pre class="code"><span style="color: blue;">void </span>Snake::bodyReshape()
{
  SnakeNode t;
  list.pop_back(t);
  footprinty=t.y;
  footprintx=t.x;
  list.retrieve(0,t);
  <span style="color: blue;">switch </span>(dir)
  {
   <span style="color: blue;">case </span>DIR_UP:
     t.y = t.y - 1;
     t.x = t.x;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">case </span>DIR_DOWN:
     t.y = t.y + 1;
     t.x = t.x;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">case </span>DIR_LEFT:
     t.y = t.y;
     t.x = t.x - 1;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">case </span>DIR_RIGHT:
     t.y = t.y;
     t.x = t.x + 1;
     <span style="color: blue;">break</span>;

   <span style="color: blue;">default</span>:
     <span style="color: blue;">break</span>;
  }
  list.insert(0,t);

}</pre>
<p>编译：</p>
<p>sudo g++ -o mySnake mySnake.cpp Screen.cpp LivingArea.cpp Snake.cpp SnakeNode.cpp Block.cpp –lncurses</p>
<p><a href="http://files.cnblogs.com/basilwang/mysnake_v2.rar">源代码下载</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2010/08/refactor-greedy-snake-cplusplus/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ubuntu 9.10 Server 配置Apache + WebDav 实现文档协同管理</title>
		<link>http://www.basilwang.net/2010/06/ubuntu-9-10-server-%e9%85%8d%e7%bd%aeapache-webdav-%e5%ae%9e%e7%8e%b0%e6%96%87%e6%a1%a3%e5%8d%8f%e5%90%8c%e7%ae%a1%e7%90%86/</link>
		<comments>http://www.basilwang.net/2010/06/ubuntu-9-10-server-%e9%85%8d%e7%bd%aeapache-webdav-%e5%ae%9e%e7%8e%b0%e6%96%87%e6%a1%a3%e5%8d%8f%e5%90%8c%e7%ae%a1%e7%90%86/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 02:49:26 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2011/09/ubuntu-9-10-server-%e9%85%8d%e7%bd%aeapache-webdav-%e5%ae%9e%e7%8e%b0%e6%96%87%e6%a1%a3%e5%8d%8f%e5%90%8c%e7%ae%a1%e7%90%86/</guid>
		<description><![CDATA[<p>先来了解一下百度百科关于WebDav（Web-based Distributed Authoring and Versioning）的解释</p> <blockquote> <p>一种基于 HTTP 1.1协议的通信协议.它扩展了HTTP 1.1，在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法，使应用程序可直接对Web Server直接读写，并支持写文件锁定(Locking)及解锁(Unlock)，还可以支持文件的版本控制。</p></blockquote> <p>下面来看如何实现文档的协同管理</p> <p>1安装软件及模块一览 </p> <p>&#160; （1）Apache2.2.14&#160; 自己下载编译。未用ubuntu 9.10 server 下apt-get安装的apache2 是因为这个版本的apache2在启用ssl的时候总是报undefined symbol apr_ldap_ssl_init错误，此处我怀疑可能是ubuntu9.10 server的问题,我在虚拟机ubuntu 8.04 desktop下配置成功。 </p> <p>2 加载Dav Module</p> <p>&#160;&#160;&#160;&#160; 在对Apache进行编译时已经开启了dav的设置（具体参见<a href="http://www.basilwang.net/2011/09/ubuntu-9-10-ssl-subversion/">Ubuntu 9.10 Server 配置基于SSL的Subversion</a>，svn需要webdav协议支持）</p><pre class="code">#sudo ./configure   –enable-dav –enable-dav-fs –enable-so   
                    –enable-ssl –enable-maintainer-mode -prefix=/usr/local/apache2   
                    –enable-mods-shared=all   </pre>
<p>&#160;&#160;&#160;&#160;&#160; 注意enable-dav和enable-dav-fs是我们文档协同所需要的。我们可以通过&#160;&#160;&#160;&#160; </p><pre class="code">cd /usr/local/apache2/bin 
sudo ./httpd -l</pre>
<p>&#160;&#160;&#160;&#160;&#160; 来查看已加载的Module。另外自主编译的方式无法通过修改httpd.conf,加入</p>
<p>LoadModule dav_module modules/mod_dav.so <br />LoadModule dav_fs_module modules/mod_dav_fs.so</p>
<p>&#160;&#160;&#160;&#160;&#160; 来完成，modules文件夹下也没有这两个so文件，启动apache后会报文件已加载，我搞了很长时间才明白这点。</p>
<p>3 配置WebDav</p>
<p>&#160;&#160; 在httpd.conf文件下 将#Include conf/extra/httpd-dav.conf的注释去掉，我们来看一下httpd-dav.conf的配置</p>
<p>DavLockDB "/usr/local/apache2/var/DavLock" </p>
<p>Alias /uploads "/usr/local/apache2/uploads"</p>
<p>&#60;Directory "/usr/local/apache2/uploads"&#62; <br />&#160;&#160;&#160; Dav On <br />&#160;&#160;&#160; Options Indexes FollowSymLinks <br />&#160;&#160;&#160; Order Allow,Deny <br />&#160;&#160;&#160; Allow from all </p>
<p>&#160;&#160;&#160; AuthType Basic <br />&#160;&#160;&#160; AuthName DAV-upload <br />&#160;&#160;&#160; Require valid-user <br />&#160;&#160;&#160; # You can use the htpasswd program to create the password database: <br />&#160;&#160;&#160; #&#160;&#160; htpasswd -c "/usr/local/apache2/user.passwd" DAV-upload admin <br />&#160;&#160;&#160; AuthUserFile "/svn/authfile"&#160; <br />&#160;&#160;&#160; &#60;Limit GET OPTIONS PUT POST DELETE PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK&#62; <br />&#160;&#160;&#160; &#60;/Limit&#62; <br />&#60;/Directory&#62;</p>
<p>注意一定是Allow from all 另外我使用了Basic的验证方法，要求用户验证;这里Subversion和WebDav使用的是同样的用户文件;Options Indexes FollowSymLinks允许我们在浏览器访问时遍历文件。</p>
<p>4 权限</p>
<p>&#160;&#160; #cd /usr/local/apache2 <br />&#160;&#160; #sudo mkdir uploads <br />&#160;&#160; #sudo chown www-data:www-data uploads <br />&#160;&#160; #sudo chmod 777 uploads <br />&#160;&#160; 以上创建上传目录并设置权限为可读可写&#160; www-data为ubuntu的用户和组</p>
<p>&#160;&#160; 另外可能需要手动创建 DavLockDB <br />&#160;&#160; #cd /usr/local/apache2 <br />&#160;&#160; #sudo mkdir var <br />&#160;&#160; #cd var <br />&#160;&#160; #sudo vim DavLock <br />&#160;&#160; #cd .. <br />&#160;&#160; #cd .. <br />&#160;&#160; #sudo chown www-data:www-data uploads <br />&#160;&#160; #sudo chmod -R 777 var/</p>
<p>5 WebDav客户端</p>
<p>&#160; 分别使用了XP和Vista自带的web folder</p>
<p>&#160;&#160; 使用方法，在XP的资源管理器下选择增加网上邻居（Vista为添加一个网络位置）输入http://your ip or sitename/uploads&#160; 并输入用户名和密码。然后再word里就可以直接对文件进行增加修改了，而且当一个用户在更改的时候，其他用户只能只读访问。</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/webfolder_3.gif"><img style="display: inline" title="webfolder_3" alt="webfolder_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/webfolder_3_thumb.gif" width="506" height="408"></a></p>
<p>当一个用户打开某文件，会加一个只读锁，其他的用户打开该文件时提示</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/conflict_3.gif"><img style="display: inline" title="conflict_3" alt="conflict_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/conflict_3_thumb.gif" width="506" height="409"></a>&#160;</p>
<p>最后附上fiddler抓到的http包,（webdav协议是http协议的扩展，所以可以观察到)</p>
<p>HTTP/1.1 207 Multi-Status <br />Date: Tue, 01 Jun 2010 08:30:34 GMT <br />Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8g DAV/2 SVN/1.6.2 <br />Content-Length: 966 <br />Keep-Alive: timeout=5, max=100 <br />Connection: Keep-Alive <br />Content-Type: text/xml; charset="utf-8" </p>
<p>&#60;?xml version="1.0" encoding="utf-8"?&#62; <br />&#60;D:multistatus xmlns:D="DAV:"&#62; <br />&#60;D:response xmlns:lp1="DAV:" xmlns:lp3="<a href="http://subversion.tigris.org/xmlns/dav/&#34;">http://subversion.tigris.org/xmlns/dav/"</a> xmlns:lp2="<a href="http://apache.org/dav/props/&#34;">http://apache.org/dav/props/"</a>&#62; <br />&#60;D:href&#62;/uploads/blackjack/Post.doc&#60;/D:href&#62; <br />&#60;D:propstat&#62; <br />&#60;D:prop&#62; <br />&#60;lp1:resourcetype/&#62; <br />&#60;lp1:creationdate&#62;2010-06-01T06:11:10Z&#60;/lp1:creationdate&#62; <br />&#60;lp1:getcontentlength&#62;46080&#60;/lp1:getcontentlength&#62; <br />&#60;lp1:getlastmodified&#62;Tue, 01 Jun 2010 06:11:10 GMT&#60;/lp1:getlastmodified&#62; <br />&#60;lp1:getetag&#62;"23a06-b400-487f1d6fea216"&#60;/lp1:getetag&#62; <br />&#60;lp2:executable&#62;F&#60;/lp2:executable&#62; <br />&#60;D:supportedlock&#62; <br />&#60;D:lockentry&#62; <br />&#60;D:lockscope&#62;&#60;D:exclusive/&#62;&#60;/D:lockscope&#62; <br />&#60;D:locktype&#62;&#60;D:write/&#62;&#60;/D:locktype&#62; <br />&#60;/D:lockentry&#62; <br />&#60;D:lockentry&#62; <br />&#60;D:lockscope&#62;&#60;D:shared/&#62;&#60;/D:lockscope&#62; <br />&#60;D:locktype&#62;&#60;D:write/&#62;&#60;/D:locktype&#62; <br />&#60;/D:lockentry&#62; <br />&#60;/D:supportedlock&#62; <br />&#60;D:lockdiscovery/&#62; <br />&#60;D:getcontenttype&#62;application/msword&#60;/D:getcontenttype&#62; <br />&#60;/D:prop&#62; <br />&#60;D:status&#62;HTTP/1.1 200 OK&#60;/D:status&#62; <br />&#60;/D:propstat&#62; <br />&#60;/D:response&#62; <br />&#60;/D:multistatus&#62;</p>]]></description>
			<content:encoded><![CDATA[<p>先来了解一下百度百科关于WebDav（Web-based Distributed Authoring and Versioning）的解释</p>
<blockquote><p>一种基于 HTTP 1.1协议的通信协议.它扩展了HTTP 1.1，在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法，使应用程序可直接对Web Server直接读写，并支持写文件锁定(Locking)及解锁(Unlock)，还可以支持文件的版本控制。</p>
</blockquote>
<p>下面来看如何实现文档的协同管理</p>
<p>1安装软件及模块一览 </p>
<p>&nbsp; （1）Apache2.2.14&nbsp; 自己下载编译。未用ubuntu 9.10 server 下apt-get安装的apache2 是因为这个版本的apache2在启用ssl的时候总是报undefined symbol apr_ldap_ssl_init错误，此处我怀疑可能是ubuntu9.10 server的问题,我在虚拟机ubuntu 8.04 desktop下配置成功。 </p>
<p>2 加载Dav Module</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 在对Apache进行编译时已经开启了dav的设置（具体参见<a href="http://www.basilwang.net/2011/09/ubuntu-9-10-ssl-subversion/">Ubuntu 9.10 Server 配置基于SSL的Subversion</a>，svn需要webdav协议支持）</p>
<pre class="code">#sudo ./configure   –enable-dav –enable-dav-fs –enable-so
                    –enable-ssl –enable-maintainer-mode -prefix=/usr/local/apache2
                    –enable-mods-shared=all   </pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意enable-dav和enable-dav-fs是我们文档协同所需要的。我们可以通过&nbsp;&nbsp;&nbsp;&nbsp; </p>
<pre class="code">cd /usr/local/apache2/bin
sudo ./httpd -l</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 来查看已加载的Module。另外自主编译的方式无法通过修改httpd.conf,加入</p>
<p>LoadModule dav_module modules/mod_dav.so <br />LoadModule dav_fs_module modules/mod_dav_fs.so</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 来完成，modules文件夹下也没有这两个so文件，启动apache后会报文件已加载，我搞了很长时间才明白这点。</p>
<p>3 配置WebDav</p>
<p>&nbsp;&nbsp; 在httpd.conf文件下 将#Include conf/extra/httpd-dav.conf的注释去掉，我们来看一下httpd-dav.conf的配置</p>
<p>DavLockDB &#8220;/usr/local/apache2/var/DavLock&#8221; </p>
<p>Alias /uploads &#8220;/usr/local/apache2/uploads&#8221;</p>
<p>&lt;Directory &#8220;/usr/local/apache2/uploads&#8221;&gt; <br />&nbsp;&nbsp;&nbsp; Dav On <br />&nbsp;&nbsp;&nbsp; Options Indexes FollowSymLinks <br />&nbsp;&nbsp;&nbsp; Order Allow,Deny <br />&nbsp;&nbsp;&nbsp; Allow from all </p>
<p>&nbsp;&nbsp;&nbsp; AuthType Basic <br />&nbsp;&nbsp;&nbsp; AuthName DAV-upload <br />&nbsp;&nbsp;&nbsp; Require valid-user <br />&nbsp;&nbsp;&nbsp; # You can use the htpasswd program to create the password database: <br />&nbsp;&nbsp;&nbsp; #&nbsp;&nbsp; htpasswd -c &#8220;/usr/local/apache2/user.passwd&#8221; DAV-upload admin <br />&nbsp;&nbsp;&nbsp; AuthUserFile &#8220;/svn/authfile&#8221;&nbsp; <br />&nbsp;&nbsp;&nbsp; &lt;Limit GET OPTIONS PUT POST DELETE PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK&gt; <br />&nbsp;&nbsp;&nbsp; &lt;/Limit&gt; <br />&lt;/Directory&gt;</p>
<p>注意一定是Allow from all 另外我使用了Basic的验证方法，要求用户验证;这里Subversion和WebDav使用的是同样的用户文件;Options Indexes FollowSymLinks允许我们在浏览器访问时遍历文件。</p>
<p>4 权限</p>
<p>&nbsp;&nbsp; #cd /usr/local/apache2 <br />&nbsp;&nbsp; #sudo mkdir uploads <br />&nbsp;&nbsp; #sudo chown www-data:www-data uploads <br />&nbsp;&nbsp; #sudo chmod 777 uploads <br />&nbsp;&nbsp; 以上创建上传目录并设置权限为可读可写&nbsp; www-data为ubuntu的用户和组</p>
<p>&nbsp;&nbsp; 另外可能需要手动创建 DavLockDB <br />&nbsp;&nbsp; #cd /usr/local/apache2 <br />&nbsp;&nbsp; #sudo mkdir var <br />&nbsp;&nbsp; #cd var <br />&nbsp;&nbsp; #sudo vim DavLock <br />&nbsp;&nbsp; #cd .. <br />&nbsp;&nbsp; #cd .. <br />&nbsp;&nbsp; #sudo chown www-data:www-data uploads <br />&nbsp;&nbsp; #sudo chmod -R 777 var/</p>
<p>5 WebDav客户端</p>
<p>&nbsp; 分别使用了XP和Vista自带的web folder</p>
<p>&nbsp;&nbsp; 使用方法，在XP的资源管理器下选择增加网上邻居（Vista为添加一个网络位置）输入http://your ip or sitename/uploads&nbsp; 并输入用户名和密码。然后再word里就可以直接对文件进行增加修改了，而且当一个用户在更改的时候，其他用户只能只读访问。</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/webfolder_3.gif"><img style="display: inline" title="webfolder_3" alt="webfolder_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/webfolder_3_thumb.gif" width="506" height="408"></a></p>
<p>当一个用户打开某文件，会加一个只读锁，其他的用户打开该文件时提示</p>
<p><a href="http://www.basilwang.net/wp-content/uploads/2011/09/conflict_3.gif"><img style="display: inline" title="conflict_3" alt="conflict_3" src="http://www.basilwang.net/wp-content/uploads/2011/09/conflict_3_thumb.gif" width="506" height="409"></a>&nbsp;</p>
<p>最后附上fiddler抓到的http包,（webdav协议是http协议的扩展，所以可以观察到)</p>
<p>HTTP/1.1 207 Multi-Status <br />Date: Tue, 01 Jun 2010 08:30:34 GMT <br />Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8g DAV/2 SVN/1.6.2 <br />Content-Length: 966 <br />Keep-Alive: timeout=5, max=100 <br />Connection: Keep-Alive <br />Content-Type: text/xml; charset=&#8221;utf-8&#8243; </p>
<p>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243;?&gt; <br />&lt;D:multistatus xmlns:D=&#8221;DAV:&#8221;&gt; <br />&lt;D:response xmlns:lp1=&#8221;DAV:&#8221; xmlns:lp3=&#8221;<a href="http://subversion.tigris.org/xmlns/dav/&quot;">http://subversion.tigris.org/xmlns/dav/&#8221;</a> xmlns:lp2=&#8221;<a href="http://apache.org/dav/props/&quot;">http://apache.org/dav/props/&#8221;</a>&gt; <br />&lt;D:href&gt;/uploads/blackjack/Post.doc&lt;/D:href&gt; <br />&lt;D:propstat&gt; <br />&lt;D:prop&gt; <br />&lt;lp1:resourcetype/&gt; <br />&lt;lp1:creationdate&gt;2010-06-01T06:11:10Z&lt;/lp1:creationdate&gt; <br />&lt;lp1:getcontentlength&gt;46080&lt;/lp1:getcontentlength&gt; <br />&lt;lp1:getlastmodified&gt;Tue, 01 Jun 2010 06:11:10 GMT&lt;/lp1:getlastmodified&gt; <br />&lt;lp1:getetag&gt;&#8221;23a06-b400-487f1d6fea216&#8243;&lt;/lp1:getetag&gt; <br />&lt;lp2:executable&gt;F&lt;/lp2:executable&gt; <br />&lt;D:supportedlock&gt; <br />&lt;D:lockentry&gt; <br />&lt;D:lockscope&gt;&lt;D:exclusive/&gt;&lt;/D:lockscope&gt; <br />&lt;D:locktype&gt;&lt;D:write/&gt;&lt;/D:locktype&gt; <br />&lt;/D:lockentry&gt; <br />&lt;D:lockentry&gt; <br />&lt;D:lockscope&gt;&lt;D:shared/&gt;&lt;/D:lockscope&gt; <br />&lt;D:locktype&gt;&lt;D:write/&gt;&lt;/D:locktype&gt; <br />&lt;/D:lockentry&gt; <br />&lt;/D:supportedlock&gt; <br />&lt;D:lockdiscovery/&gt; <br />&lt;D:getcontenttype&gt;application/msword&lt;/D:getcontenttype&gt; <br />&lt;/D:prop&gt; <br />&lt;D:status&gt;HTTP/1.1 200 OK&lt;/D:status&gt; <br />&lt;/D:propstat&gt; <br />&lt;/D:response&gt; <br />&lt;/D:multistatus&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2010/06/ubuntu-9-10-server-%e9%85%8d%e7%bd%aeapache-webdav-%e5%ae%9e%e7%8e%b0%e6%96%87%e6%a1%a3%e5%8d%8f%e5%90%8c%e7%ae%a1%e7%90%86/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>javascript事件机制与jQuery.bind的补充说明</title>
		<link>http://www.basilwang.net/2010/05/javascript-event-jquery-bind-more/</link>
		<comments>http://www.basilwang.net/2010/05/javascript-event-jquery-bind-more/#comments</comments>
		<pubDate>Mon, 10 May 2010 02:43:55 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2011/09/javascript%e4%ba%8b%e4%bb%b6%e6%9c%ba%e5%88%b6%e4%b8%8ejquery-bind%e7%9a%84%e8%a1%a5%e5%85%85%e8%af%b4%e6%98%8e/</guid>
		<description><![CDATA[在之前的文章<a href="http://www.basilwang.net/2010/05/javascript-event-jquery-bind/" target="_blank">javascript 事件机制 与 jQuery.Bind</a>中，为了说明冒泡阶段中Event Handler Function的表现，我使用了event.data来记录触发function的次数。并且提出了一个问题，就是在jQuery.bind方式中,event.data无法正确记录触发的次数。后来经过测试和查阅网上的相关的资料，得出了一个结论，就是我之前关于event.data的使用方式是错误的，或者说对于跨浏览器的支持是困难的。同时我也意识到，由于event.data在w3c dom level 2文档中，并不是作为event的标准属性出现的，所以jQuery对event进行了fix,使其能够兼容各个浏览器。

在我纠正误用event.data的方式之前，再描述一下我对event的理解。在我查看jQuery(1.3.2)源代码的时候，jQuery.event的add方法中有如下代码
<pre class="code"><span style="color: green;">// Init the element's event structure
</span><span style="color: blue;">var </span>events = jQuery.data(elem, <span style="color: #a31515;">"events"</span>) &#124;&#124; jQuery.data(elem, <span style="color: #a31515;">"events"</span>, {}),
    handle = jQuery.data(elem, <span style="color: #a31515;">"handle"</span>) &#124;&#124; jQuery.data(elem, <span style="color: #a31515;">"handle"</span>, <span style="color: blue;">function</span>() {
         <span style="color: green;">// Handle the second event of a trigger and when
         // an event is called after a page has unloaded
         </span><span style="color: blue;">return typeof </span>jQuery !== <span style="color: #a31515;">"undefined" </span>&#38;&#38; !jQuery.event.triggered ?
                jQuery.event.handle.apply(arguments.callee.elem, arguments) :
                undefined;
        });</pre>
其中的jQuery.event.handle中进行event的fix
<pre class="code">event = arguments[0] = jQuery.event.fix(event &#124;&#124; window.event);</pre>
这里按照网上的资料大多是说ie下使用window.event,而firefox下使用arguments[0]也就是传递过来的函数参数event。可我在测试中发现ie6,ie7(未测试）,ie8在fix之前event并不为空，也就是说在fix的时候并没有使用window.event。

看一下这段代码
<pre class="code"><span style="color: blue;">&#60;!</span><span style="color: #a31515;">DOCTYPE </span><span style="color: red;">html PUBLIC </span><span style="color: blue;">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&#62;
&#60;</span><span style="color: #a31515;">html </span><span style="color: red;">xmlns</span><span style="color: blue;">="http://www.w3.org/1999/xhtml" </span><span style="color: red;">lang</span><span style="color: blue;">="zh-CN"&#62;
&#60;</span><span style="color: #a31515;">head</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">meta </span><span style="color: red;">http-equiv</span><span style="color: blue;">="Content-Type" </span><span style="color: red;">content</span><span style="color: blue;">="text/html; charset=utf-8"    /&#62;
&#60;</span><span style="color: #a31515;">title</span><span style="color: blue;">&#62;&#60;/</span><span style="color: #a31515;">title</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">style</span><span style="color: blue;">&#62;
     </span><span style="color: #a31515;">#panelGrandPa</span>,<span style="color: #a31515;">#panelPaPa</span>,<span style="color: #a31515;">#panelSon  </span>{ <span style="color: red;">border</span>:<span style="color: blue;">1px  solid #320213</span>;}
 <span style="color: blue;">&#60;/</span><span style="color: #a31515;">style</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">head</span><span style="color: blue;">&#62;
 &#60;</span><span style="color: #a31515;">body</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelGrandPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">300px</span>;<span style="color: red;">height</span>:<span style="color: blue;">200px</span>;<span style="color: blue;">" &#62;
       &#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelPaPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">200px</span>;<span style="color: red;">height</span>:<span style="color: blue;">100px</span>;<span style="color: blue;">" &#62;
            &#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelSon" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">100px</span>;<span style="color: red;">height</span>:<span style="color: blue;">50px</span>;<span style="color: blue;">" &#62;

            &#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
       &#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">script</span><span style="color: blue;">&#62;
    function </span>click() {
        alert(event.srcElement.id);
        event.data = event.data &#124;&#124; 1;
        alert(<span style="color: #a31515;">"click function has fired  " </span>+ event.data + <span style="color: #a31515;">" times"</span>);
        event.data = parseInt(event.data) + 1;
    }
    <span style="color: blue;">function </span>clickSon() {
        alert(<span style="color: #a31515;">"I am son"</span>);
        click();
    }
    <span style="color: blue;">function </span>clickGrandPa() {
        alert(<span style="color: #a31515;">"I am GrandPa"</span>);
        click();
    }
    document.getElementById(<span style="color: #a31515;">"panelGrandPa"</span>).onclick = clickGrandPa;
    document.getElementById(<span style="color: #a31515;">"panelSon"</span>).onclick = clickSon;
<span style="color: blue;">&#60;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">body</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">html</span><span style="color: blue;">&#62;</span><span style="color: blue;">
</span></pre>
只能在ie8下正常工作，在ie6和ie7下都报event.data undefined错误。当然我们这里使用的是window.event也就是页面维护的event相当于全局变量，那我们再试一下事件方法的event参数（之前阅读jQuery源代码提到的ie中除却window.event另外的event）
<pre class="code"><span style="color: blue;">&#60;!</span><span style="color: #a31515;">DOCTYPE </span><span style="color: red;">html PUBLIC </span><span style="color: blue;">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&#62;
&#60;</span><span style="color: #a31515;">html </span><span style="color: red;">xmlns</span><span style="color: blue;">="http://www.w3.org/1999/xhtml" </span><span style="color: red;">lang</span><span style="color: blue;">="zh-CN"&#62;
&#60;</span><span style="color: #a31515;">head</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">meta </span><span style="color: red;">http-equiv</span><span style="color: blue;">="Content-Type" </span><span style="color: red;">content</span><span style="color: blue;">="text/html; charset=utf-8"    /&#62;
&#60;</span><span style="color: #a31515;">title</span><span style="color: blue;">&#62;&#60;/</span><span style="color: #a31515;">title</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">style</span><span style="color: blue;">&#62;
     </span><span style="color: #a31515;">#panelGrandPa</span>,<span style="color: #a31515;">#panelPaPa</span>,<span style="color: #a31515;">#panelSon  </span>{ <span style="color: red;">border</span>:<span style="color: blue;">1px  solid #320213</span>;}
 <span style="color: blue;">&#60;/</span><span style="color: #a31515;">style</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">head</span><span style="color: blue;">&#62;
 &#60;</span><span style="color: #a31515;">body</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelGrandPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">300px</span>;<span style="color: red;">height</span>:<span style="color: blue;">200px</span>;<span style="color: blue;">" &#62;
       &#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelPaPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">200px</span>;<span style="color: red;">height</span>:<span style="color: blue;">100px</span>;<span style="color: blue;">" &#62;
            &#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelSon" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">100px</span>;<span style="color: red;">height</span>:<span style="color: blue;">50px</span>;<span style="color: blue;">" &#62;

            &#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
       &#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">script</span><span style="color: blue;">&#62;
    function </span>click(e) {
        alert(event.srcElement.id);
        e.data = e.data &#124;&#124; 1;
        alert(<span style="color: #a31515;">"click function has fired  " </span>+ e.data + <span style="color: #a31515;">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue;">function </span>clickSon() {
        alert(<span style="color: #a31515;">"I am son"</span>);
        click(arguments[0]);
    }
    <span style="color: blue;">function </span>clickGrandPa() {
        alert(<span style="color: #a31515;">"I am GrandPa"</span>);
        click(arguments[0]);
    }
    document.getElementById(<span style="color: #a31515;">"panelGrandPa"</span>).attachEvent(<span style="color: #a31515;">"onclick"</span>, clickGrandPa);
    document.getElementById(<span style="color: #a31515;">"panelSon"</span>).attachEvent(<span style="color: #a31515;">"onclick"</span>, clickSon);
<span style="color: blue;">&#60;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">body</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">html</span><span style="color: blue;">&#62;
</span></pre>
注意必须用attachEvent我们才能得到区别于window.event的“另一个”event。以上代码在ie8下正常工作，在ie6和ie7下event.data始终为1

对于window.event，在ie6和ie7下，通过调试工具发现其中并没有event.data的属性。而attachEvent的得到的event.data 在ie6和ie7下不能正确计数，始终为1，但ie8下正确。

鉴于event在各浏览器下的差异以及我们对书写跨浏览器脚本的良好愿望，我个人认为不应该在多个事件方法中传递event.data。

当然jQuery在这方面做得更好经过fix后的event 使得event.data在各种浏览器下表现一致
<pre class="code"><span style="color: blue;">&#60;!</span><span style="color: #a31515;">DOCTYPE </span><span style="color: red;">html PUBLIC </span><span style="color: blue;">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&#62;
&#60;</span><span style="color: #a31515;">html </span><span style="color: red;">xmlns</span><span style="color: blue;">="http://www.w3.org/1999/xhtml" </span><span style="color: red;">lang</span><span style="color: blue;">="zh-CN"&#62;
&#60;</span><span style="color: #a31515;">head</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">meta </span><span style="color: red;">http-equiv</span><span style="color: blue;">="Content-Type" </span><span style="color: red;">content</span><span style="color: blue;">="text/html; charset=utf-8"    /&#62;
 &#60;</span><span style="color: #a31515;">script </span><span style="color: red;">type</span><span style="color: blue;">="text/javascript" </span><span style="color: red;">src</span><span style="color: blue;">="http://jqueryjs.googlecode.com/files/jquery-1.3.2.js"&#62;&#60;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">title</span><span style="color: blue;">&#62;&#60;/</span><span style="color: #a31515;">title</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">style</span><span style="color: blue;">&#62;
     </span><span style="color: #a31515;">#panelGrandPa</span>,<span style="color: #a31515;">#panelPaPa</span>,<span style="color: #a31515;">#panelSon  </span>{ <span style="color: red;">border</span>:<span style="color: blue;">1px  solid #320213</span>;}
 <span style="color: blue;">&#60;/</span><span style="color: #a31515;">style</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">head</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">body</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelGrandPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">300px</span>;<span style="color: red;">height</span>:<span style="color: blue;">200px</span>;<span style="color: blue;">" &#62;
       &#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelPaPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">200px</span>;<span style="color: red;">height</span>:<span style="color: blue;">100px</span>;<span style="color: blue;">" &#62;
            &#60;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelSon" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">100px</span>;<span style="color: red;">height</span>:<span style="color: blue;">50px</span>;<span style="color: blue;">" &#62;

            &#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
       &#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&#62;
&#60;</span><span style="color: #a31515;">script</span><span style="color: blue;">&#62;
    function </span>click(e) {
        alert(e.target.id);
        e.data = e.data &#124;&#124; 1;
        alert(<span style="color: #a31515;">"click function has fired  " </span>+ e.data + <span style="color: #a31515;">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue;">function </span>clickSon(e) {
        alert(<span style="color: #a31515;">"I am son"</span>);
        click(e);
    }
    <span style="color: blue;">function </span>clickGrandPa(e) {
        alert(<span style="color: #a31515;">"I am GrandPa"</span>);
        click(e);
    }
    $(<span style="color: #a31515;">"#panelGrandPa"</span>).bind(<span style="color: #a31515;">"click"</span>, clickGrandPa);
    $(<span style="color: #a31515;">"#panelSon"</span>).bind(<span style="color: #a31515;">"click"</span>, clickSon);
<span style="color: blue;">&#60;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">body</span><span style="color: blue;">&#62;
&#60;/</span><span style="color: #a31515;">html</span><span style="color: blue;">&#62;
</span></pre>
上述代码在任何浏览器下都不能正常计数，显示event.data为1（这下ie8也不行了）。

我们分析一下原因，这也是我对上一篇提出问题的一个回答

jQuery.event.add方法封装了attachEvent/addEventListener并且给每一个handler方法附加了data
<pre class="code">add:<span style="color: blue;">function</span>(elem, types, handler, data) {
    <span style="color: green;">//省略部分代码
    // if data is passed, bind to handler
    </span><span style="color: blue;">if </span>(data !== undefined) {
        <span style="color: green;">// Create temporary function pointer to original handler
        </span><span style="color: blue;">var </span>fn = handler;

        <span style="color: green;">// Create unique handler function, wrapped around original handler
        </span>handler = <span style="color: blue;">this</span>.proxy(fn);

        <span style="color: green;">// Store data in unique handler
        </span>handler.data = data;
    }
    <span style="color: green;">//省略部分代码
</span>}</pre>
在jQuery.event的fix方法中，我们看到其将传入的event复制了一份（包括data)，注意不是引用（这意味着每次方法的event都是不同的）
<pre class="code">fix: <span style="color: blue;">function</span>(event) {
    <span style="color: blue;">if </span>(event[expando])
        <span style="color: blue;">return </span>event;

    <span style="color: green;">// store a copy of the original event object
    // and "clone" to set read-only properties
    </span><span style="color: blue;">var </span>originalEvent = event;
    event = jQuery.Event(originalEvent);

    <span style="color: blue;">for </span>(<span style="color: blue;">var </span>i = <span style="color: blue;">this</span>.props.length, prop; i; ) {
        prop = <span style="color: blue;">this</span>.props[--i];
        event[prop] = originalEvent[prop];
    }
    <span style="color: green;">//以下省略
</span>}</pre>
那么这样一来，我们肯定不能在多个事件方法中用上述方法传递data了。]]></description>
			<content:encoded><![CDATA[<p>在之前的文章<a href="http://www.basilwang.net/2010/05/javascript-event-jquery-bind/" target="_blank">javascript 事件机制 与 jQuery.Bind</a>中，为了说明冒泡阶段中Event Handler Function的表现，我使用了event.data来记录触发function的次数。并且提出了一个问题，就是在jQuery.bind方式中,event.data无法正确记录触发的次数。后来经过测试和查阅网上的相关的资料，得出了一个结论，就是我之前关于event.data的使用方式是错误的，或者说对于跨浏览器的支持是困难的。同时我也意识到，由于event.data在w3c dom level 2文档中，并不是作为event的标准属性出现的，所以jQuery对event进行了fix,使其能够兼容各个浏览器。</p>
<p>在我纠正误用event.data的方式之前，再描述一下我对event的理解。在我查看jQuery(1.3.2)源代码的时候，jQuery.event的add方法中有如下代码</p>
<pre class="code"><span style="color: green;">// Init the element's event structure
</span><span style="color: blue;">var </span>events = jQuery.data(elem, <span style="color: #a31515;">"events"</span>) || jQuery.data(elem, <span style="color: #a31515;">"events"</span>, {}),
    handle = jQuery.data(elem, <span style="color: #a31515;">"handle"</span>) || jQuery.data(elem, <span style="color: #a31515;">"handle"</span>, <span style="color: blue;">function</span>() {
         <span style="color: green;">// Handle the second event of a trigger and when
         // an event is called after a page has unloaded
         </span><span style="color: blue;">return typeof </span>jQuery !== <span style="color: #a31515;">"undefined" </span>&amp;&amp; !jQuery.event.triggered ?
                jQuery.event.handle.apply(arguments.callee.elem, arguments) :
                undefined;
        });</pre>
<p>其中的jQuery.event.handle中进行event的fix</p>
<pre class="code">event = arguments[0] = jQuery.event.fix(event || window.event);</pre>
<p>这里按照网上的资料大多是说ie下使用window.event,而firefox下使用arguments[0]也就是传递过来的函数参数event。可我在测试中发现ie6,ie7(未测试）,ie8在fix之前event并不为空，也就是说在fix的时候并没有使用window.event。</p>
<p>看一下这段代码</p>
<pre class="code"><span style="color: blue;">&lt;!</span><span style="color: #a31515;">DOCTYPE </span><span style="color: red;">html PUBLIC </span><span style="color: blue;">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;</span><span style="color: #a31515;">html </span><span style="color: red;">xmlns</span><span style="color: blue;">="http://www.w3.org/1999/xhtml" </span><span style="color: red;">lang</span><span style="color: blue;">="zh-CN"&gt;
&lt;</span><span style="color: #a31515;">head</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">meta </span><span style="color: red;">http-equiv</span><span style="color: blue;">="Content-Type" </span><span style="color: red;">content</span><span style="color: blue;">="text/html; charset=utf-8"    /&gt;
&lt;</span><span style="color: #a31515;">title</span><span style="color: blue;">&gt;&lt;/</span><span style="color: #a31515;">title</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">style</span><span style="color: blue;">&gt;
     </span><span style="color: #a31515;">#panelGrandPa</span>,<span style="color: #a31515;">#panelPaPa</span>,<span style="color: #a31515;">#panelSon  </span>{ <span style="color: red;">border</span>:<span style="color: blue;">1px  solid #320213</span>;}
 <span style="color: blue;">&lt;/</span><span style="color: #a31515;">style</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">head</span><span style="color: blue;">&gt;
 &lt;</span><span style="color: #a31515;">body</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelGrandPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">300px</span>;<span style="color: red;">height</span>:<span style="color: blue;">200px</span>;<span style="color: blue;">" &gt;
       &lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelPaPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">200px</span>;<span style="color: red;">height</span>:<span style="color: blue;">100px</span>;<span style="color: blue;">" &gt;
            &lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelSon" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">100px</span>;<span style="color: red;">height</span>:<span style="color: blue;">50px</span>;<span style="color: blue;">" &gt;

            &lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
       &lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">script</span><span style="color: blue;">&gt;
    function </span>click() {
        alert(event.srcElement.id);
        event.data = event.data || 1;
        alert(<span style="color: #a31515;">"click function has fired  " </span>+ event.data + <span style="color: #a31515;">" times"</span>);
        event.data = parseInt(event.data) + 1;
    }
    <span style="color: blue;">function </span>clickSon() {
        alert(<span style="color: #a31515;">"I am son"</span>);
        click();
    }
    <span style="color: blue;">function </span>clickGrandPa() {
        alert(<span style="color: #a31515;">"I am GrandPa"</span>);
        click();
    }
    document.getElementById(<span style="color: #a31515;">"panelGrandPa"</span>).onclick = clickGrandPa;
    document.getElementById(<span style="color: #a31515;">"panelSon"</span>).onclick = clickSon;
<span style="color: blue;">&lt;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">body</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">html</span><span style="color: blue;">&gt;</span><span style="color: blue;">
</span></pre>
<p>只能在ie8下正常工作，在ie6和ie7下都报event.data undefined错误。当然我们这里使用的是window.event也就是页面维护的event相当于全局变量，那我们再试一下事件方法的event参数（之前阅读jQuery源代码提到的ie中除却window.event另外的event）</p>
<pre class="code"><span style="color: blue;">&lt;!</span><span style="color: #a31515;">DOCTYPE </span><span style="color: red;">html PUBLIC </span><span style="color: blue;">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;</span><span style="color: #a31515;">html </span><span style="color: red;">xmlns</span><span style="color: blue;">="http://www.w3.org/1999/xhtml" </span><span style="color: red;">lang</span><span style="color: blue;">="zh-CN"&gt;
&lt;</span><span style="color: #a31515;">head</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">meta </span><span style="color: red;">http-equiv</span><span style="color: blue;">="Content-Type" </span><span style="color: red;">content</span><span style="color: blue;">="text/html; charset=utf-8"    /&gt;
&lt;</span><span style="color: #a31515;">title</span><span style="color: blue;">&gt;&lt;/</span><span style="color: #a31515;">title</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">style</span><span style="color: blue;">&gt;
     </span><span style="color: #a31515;">#panelGrandPa</span>,<span style="color: #a31515;">#panelPaPa</span>,<span style="color: #a31515;">#panelSon  </span>{ <span style="color: red;">border</span>:<span style="color: blue;">1px  solid #320213</span>;}
 <span style="color: blue;">&lt;/</span><span style="color: #a31515;">style</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">head</span><span style="color: blue;">&gt;
 &lt;</span><span style="color: #a31515;">body</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelGrandPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">300px</span>;<span style="color: red;">height</span>:<span style="color: blue;">200px</span>;<span style="color: blue;">" &gt;
       &lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelPaPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">200px</span>;<span style="color: red;">height</span>:<span style="color: blue;">100px</span>;<span style="color: blue;">" &gt;
            &lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelSon" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">100px</span>;<span style="color: red;">height</span>:<span style="color: blue;">50px</span>;<span style="color: blue;">" &gt;

            &lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
       &lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">script</span><span style="color: blue;">&gt;
    function </span>click(e) {
        alert(event.srcElement.id);
        e.data = e.data || 1;
        alert(<span style="color: #a31515;">"click function has fired  " </span>+ e.data + <span style="color: #a31515;">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue;">function </span>clickSon() {
        alert(<span style="color: #a31515;">"I am son"</span>);
        click(arguments[0]);
    }
    <span style="color: blue;">function </span>clickGrandPa() {
        alert(<span style="color: #a31515;">"I am GrandPa"</span>);
        click(arguments[0]);
    }
    document.getElementById(<span style="color: #a31515;">"panelGrandPa"</span>).attachEvent(<span style="color: #a31515;">"onclick"</span>, clickGrandPa);
    document.getElementById(<span style="color: #a31515;">"panelSon"</span>).attachEvent(<span style="color: #a31515;">"onclick"</span>, clickSon);
<span style="color: blue;">&lt;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">body</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">html</span><span style="color: blue;">&gt;
</span></pre>
<p>注意必须用attachEvent我们才能得到区别于window.event的“另一个”event。以上代码在ie8下正常工作，在ie6和ie7下event.data始终为1</p>
<p>对于window.event，在ie6和ie7下，通过调试工具发现其中并没有event.data的属性。而attachEvent的得到的event.data 在ie6和ie7下不能正确计数，始终为1，但ie8下正确。</p>
<p>鉴于event在各浏览器下的差异以及我们对书写跨浏览器脚本的良好愿望，我个人认为不应该在多个事件方法中传递event.data。</p>
<p>当然jQuery在这方面做得更好经过fix后的event 使得event.data在各种浏览器下表现一致</p>
<pre class="code"><span style="color: blue;">&lt;!</span><span style="color: #a31515;">DOCTYPE </span><span style="color: red;">html PUBLIC </span><span style="color: blue;">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;</span><span style="color: #a31515;">html </span><span style="color: red;">xmlns</span><span style="color: blue;">="http://www.w3.org/1999/xhtml" </span><span style="color: red;">lang</span><span style="color: blue;">="zh-CN"&gt;
&lt;</span><span style="color: #a31515;">head</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">meta </span><span style="color: red;">http-equiv</span><span style="color: blue;">="Content-Type" </span><span style="color: red;">content</span><span style="color: blue;">="text/html; charset=utf-8"    /&gt;
 &lt;</span><span style="color: #a31515;">script </span><span style="color: red;">type</span><span style="color: blue;">="text/javascript" </span><span style="color: red;">src</span><span style="color: blue;">="http://jqueryjs.googlecode.com/files/jquery-1.3.2.js"&gt;&lt;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">title</span><span style="color: blue;">&gt;&lt;/</span><span style="color: #a31515;">title</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">style</span><span style="color: blue;">&gt;
     </span><span style="color: #a31515;">#panelGrandPa</span>,<span style="color: #a31515;">#panelPaPa</span>,<span style="color: #a31515;">#panelSon  </span>{ <span style="color: red;">border</span>:<span style="color: blue;">1px  solid #320213</span>;}
 <span style="color: blue;">&lt;/</span><span style="color: #a31515;">style</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">head</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">body</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelGrandPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">300px</span>;<span style="color: red;">height</span>:<span style="color: blue;">200px</span>;<span style="color: blue;">" &gt;
       &lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelPaPa" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">200px</span>;<span style="color: red;">height</span>:<span style="color: blue;">100px</span>;<span style="color: blue;">" &gt;
            &lt;</span><span style="color: #a31515;">div </span><span style="color: red;">id</span><span style="color: blue;">="panelSon" </span><span style="color: red;">style</span><span style="color: blue;">="</span><span style="color: red;">width</span>:<span style="color: blue;">100px</span>;<span style="color: red;">height</span>:<span style="color: blue;">50px</span>;<span style="color: blue;">" &gt;

            &lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
       &lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">div</span><span style="color: blue;">&gt;
&lt;</span><span style="color: #a31515;">script</span><span style="color: blue;">&gt;
    function </span>click(e) {
        alert(e.target.id);
        e.data = e.data || 1;
        alert(<span style="color: #a31515;">"click function has fired  " </span>+ e.data + <span style="color: #a31515;">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue;">function </span>clickSon(e) {
        alert(<span style="color: #a31515;">"I am son"</span>);
        click(e);
    }
    <span style="color: blue;">function </span>clickGrandPa(e) {
        alert(<span style="color: #a31515;">"I am GrandPa"</span>);
        click(e);
    }
    $(<span style="color: #a31515;">"#panelGrandPa"</span>).bind(<span style="color: #a31515;">"click"</span>, clickGrandPa);
    $(<span style="color: #a31515;">"#panelSon"</span>).bind(<span style="color: #a31515;">"click"</span>, clickSon);
<span style="color: blue;">&lt;/</span><span style="color: #a31515;">script</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">body</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">html</span><span style="color: blue;">&gt;
</span></pre>
<p>上述代码在任何浏览器下都不能正常计数，显示event.data为1（这下ie8也不行了）。</p>
<p>我们分析一下原因，这也是我对上一篇提出问题的一个回答</p>
<p>jQuery.event.add方法封装了attachEvent/addEventListener并且给每一个handler方法附加了data</p>
<pre class="code">add:<span style="color: blue;">function</span>(elem, types, handler, data) {
    <span style="color: green;">//省略部分代码
    // if data is passed, bind to handler
    </span><span style="color: blue;">if </span>(data !== undefined) {
        <span style="color: green;">// Create temporary function pointer to original handler
        </span><span style="color: blue;">var </span>fn = handler;

        <span style="color: green;">// Create unique handler function, wrapped around original handler
        </span>handler = <span style="color: blue;">this</span>.proxy(fn);

        <span style="color: green;">// Store data in unique handler
        </span>handler.data = data;
    }
    <span style="color: green;">//省略部分代码
</span>}</pre>
<p>在jQuery.event的fix方法中，我们看到其将传入的event复制了一份（包括data)，注意不是引用（这意味着每次方法的event都是不同的）</p>
<pre class="code">fix: <span style="color: blue;">function</span>(event) {
    <span style="color: blue;">if </span>(event[expando])
        <span style="color: blue;">return </span>event;

    <span style="color: green;">// store a copy of the original event object
    // and "clone" to set read-only properties
    </span><span style="color: blue;">var </span>originalEvent = event;
    event = jQuery.Event(originalEvent);

    <span style="color: blue;">for </span>(<span style="color: blue;">var </span>i = <span style="color: blue;">this</span>.props.length, prop; i; ) {
        prop = <span style="color: blue;">this</span>.props[--i];
        event[prop] = originalEvent[prop];
    }
    <span style="color: green;">//以下省略
</span>}</pre>
<p>那么这样一来，我们肯定不能在多个事件方法中用上述方法传递data了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2010/05/javascript-event-jquery-bind-more/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>javascript 事件机制 与 jQuery.Bind</title>
		<link>http://www.basilwang.net/2010/05/javascript-event-jquery-bind/</link>
		<comments>http://www.basilwang.net/2010/05/javascript-event-jquery-bind/#comments</comments>
		<pubDate>Sat, 08 May 2010 02:41:00 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.basilwang.net/2010/05/javascript-%e4%ba%8b%e4%bb%b6%e6%9c%ba%e5%88%b6-%e4%b8%8e-jquery-bind/</guid>
		<description><![CDATA[<p>W3C DOM Level2的事件模型规范中，事件在DOM树中的传播过程（从根节点到目标节点）被分为了两个阶段：<a href="http://www.basilwang.net/wp-content/uploads/2011/09/jquerybind1.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="jquerybind" border="0" alt="jquerybind" align="left" src="http://www.basilwang.net/wp-content/uploads/2011/09/jquerybind_thumb1.jpg" width="275" height="263"></a>捕捉（Capture）和冒泡（Bubbling）,而事件在传递的过程中需要先经历Capture Phrase后经历Bubble Phrase 。在firefox下，我们可以用target.addEventListener(type, listener, useCapture),第三个参数指定是否为Capture；但IE不支持捕获，而且jQuery也不支持Capture(不过我觉得Bubbling足够了）。因此后面的讨论主要在Bubbling阶段。首先看一下IE下实现事件模型的代码。</p> <p>请在IE8运行以下代码(只能在ie8下运行)</p><pre class="code"><span style="color: blue">&#60;!</span><span style="color: #a31515">DOCTYPE </span><span style="color: red">html PUBLIC </span><span style="color: blue">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&#62;
&#60;</span><span style="color: #a31515">html </span><span style="color: red">xmlns</span><span style="color: blue">="http://www.w3.org/1999/xhtml" </span><span style="color: red">lang</span><span style="color: blue">="zh-CN"&#62;
&#60;</span><span style="color: #a31515">head</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">meta </span><span style="color: red">http-equiv</span><span style="color: blue">="Content-Type" </span><span style="color: red">content</span><span style="color: blue">="text/html; charset=utf-8"    /&#62;
&#60;</span><span style="color: #a31515">title</span><span style="color: blue">&#62;&#60;/</span><span style="color: #a31515">title</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">style</span><span style="color: blue">&#62;
     </span><span style="color: #a31515">#panelGrandPa</span>,<span style="color: #a31515">#panelPaPa</span>,<span style="color: #a31515">#panelSon  </span>{ <span style="color: red">border</span>:<span style="color: blue">1px  solid #320213</span>;}
 <span style="color: blue">&#60;/</span><span style="color: #a31515">style</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">head</span><span style="color: blue">&#62;
 &#60;</span><span style="color: #a31515">body</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelGrandPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">300px</span>;<span style="color: red">height</span>:<span style="color: blue">200px</span>;<span style="color: blue">" &#62;
       &#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelPaPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">200px</span>;<span style="color: red">height</span>:<span style="color: blue">100px</span>;<span style="color: blue">" &#62;
            &#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelSon" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">100px</span>;<span style="color: red">height</span>:<span style="color: blue">50px</span>;<span style="color: blue">" &#62;

            &#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
       &#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">script</span><span style="color: blue">&#62;
    function </span>click() {
        alert(event.srcElement.id);
        event.data = event.data &#124;&#124; 1;
        alert(<span style="color: #a31515">"click function has fired  " </span>+ event.data + <span style="color: #a31515">" times"</span>);
        event.data = parseInt(event.data) + 1;
    }
    <span style="color: blue">function </span>clickSon() {
        alert(<span style="color: #a31515">"I am son"</span>);
        click();
    }
    <span style="color: blue">function </span>clickGrandPa() {
        alert(<span style="color: #a31515">"I am GrandPa"</span>);
        click();
    }
    document.getElementById(<span style="color: #a31515">"panelGrandPa"</span>).onclick = clickGrandPa;
    document.getElementById(<span style="color: #a31515">"panelSon"</span>).onclick = clickSon;
<span style="color: blue">&#60;/</span><span style="color: #a31515">script</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">body</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">html</span><span style="color: blue">&#62;

</span></pre>
<p><br />注意传统element.onclick或者element['on'+eventName]，这个是所有浏览器都支持的事件绑定的监听器，但由于上述代码使用了event.srcElement.id，因此只能在IE8下运行。下面看一下在firefox下的使用，这里我们采用了符合W3C DOM的target.addEventListener(type, listener, useCapture)，另外使用了event.target.id。<br />请在firefox,chrome下运行以下代码<br /></p><pre class="code"><span style="color: blue">&#60;!</span><span style="color: #a31515">DOCTYPE </span><span style="color: red">html PUBLIC </span><span style="color: blue">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&#62;
&#60;</span><span style="color: #a31515">html </span><span style="color: red">xmlns</span><span style="color: blue">="http://www.w3.org/1999/xhtml" </span><span style="color: red">lang</span><span style="color: blue">="zh-CN"&#62;
&#60;</span><span style="color: #a31515">head</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">meta </span><span style="color: red">http-equiv</span><span style="color: blue">="Content-Type" </span><span style="color: red">content</span><span style="color: blue">="text/html; charset=utf-8"    /&#62;
&#60;</span><span style="color: #a31515">title</span><span style="color: blue">&#62;&#60;/</span><span style="color: #a31515">title</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">style</span><span style="color: blue">&#62;
     </span><span style="color: #a31515">#panelGrandPa</span>,<span style="color: #a31515">#panelPaPa</span>,<span style="color: #a31515">#panelSon  </span>{ <span style="color: red">border</span>:<span style="color: blue">1px  solid #320213</span>;}
 <span style="color: blue">&#60;/</span><span style="color: #a31515">style</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">head</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">body</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelGrandPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">300px</span>;<span style="color: red">height</span>:<span style="color: blue">200px</span>;<span style="color: blue">" &#62;
       &#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelPaPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">200px</span>;<span style="color: red">height</span>:<span style="color: blue">100px</span>;<span style="color: blue">" &#62;
            &#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelSon" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">100px</span>;<span style="color: red">height</span>:<span style="color: blue">50px</span>;<span style="color: blue">" &#62;

            &#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
       &#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">script</span><span style="color: blue">&#62;
    function </span>click(e) {
        alert(e.target.id);
        e.data = e.data &#124;&#124; 1;
        alert(<span style="color: #a31515">"click function has fired  " </span>+ e.data + <span style="color: #a31515">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue">function </span>clickSon(e) {
        alert(<span style="color: #a31515">"I am son"</span>);
        click(e);
    }
    <span style="color: blue">function </span>clickGrandPa(e) {
        alert(<span style="color: #a31515">"I am GrandPa"</span>);
        click(e);
    }
    document.getElementById(<span style="color: #a31515">"panelGrandPa"</span>).addEventListener(<span style="color: #a31515">"click"</span>, clickGrandPa, <span style="color: blue">false</span>);
    document.getElementById(<span style="color: #a31515">"panelSon"</span>).addEventListener(<span style="color: #a31515">"click"</span>, clickSon, <span style="color: blue">false</span>);
<span style="color: blue">&#60;/</span><span style="color: #a31515">script</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">body</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">html</span><span style="color: blue">&#62;
</span></pre>
<p><br />那么在jQuery中我们是怎么处理的呢<br /></p><pre class="code"><span style="color: blue">&#60;!</span><span style="color: #a31515">DOCTYPE </span><span style="color: red">html PUBLIC </span><span style="color: blue">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&#62;
&#60;</span><span style="color: #a31515">html </span><span style="color: red">xmlns</span><span style="color: blue">="http://www.w3.org/1999/xhtml" </span><span style="color: red">lang</span><span style="color: blue">="zh-CN"&#62;
&#60;</span><span style="color: #a31515">head</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">meta </span><span style="color: red">http-equiv</span><span style="color: blue">="Content-Type" </span><span style="color: red">content</span><span style="color: blue">="text/html; charset=utf-8"    /&#62;
 &#60;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">="text/javascript" </span><span style="color: red">src</span><span style="color: blue">="http://jqueryjs.googlecode.com/files/jquery-1.3.2.js"&#62;&#60;/</span><span style="color: #a31515">script</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">title</span><span style="color: blue">&#62;&#60;/</span><span style="color: #a31515">title</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">style</span><span style="color: blue">&#62;
     </span><span style="color: #a31515">#panelGrandPa</span>,<span style="color: #a31515">#panelPaPa</span>,<span style="color: #a31515">#panelSon  </span>{ <span style="color: red">border</span>:<span style="color: blue">1px  solid #320213</span>;}
 <span style="color: blue">&#60;/</span><span style="color: #a31515">style</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">head</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">body</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelGrandPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">300px</span>;<span style="color: red">height</span>:<span style="color: blue">200px</span>;<span style="color: blue">" &#62;
       &#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelPaPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">200px</span>;<span style="color: red">height</span>:<span style="color: blue">100px</span>;<span style="color: blue">" &#62;
            &#60;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelSon" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">100px</span>;<span style="color: red">height</span>:<span style="color: blue">50px</span>;<span style="color: blue">" &#62;

            &#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
       &#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">div</span><span style="color: blue">&#62;
&#60;</span><span style="color: #a31515">script</span><span style="color: blue">&#62;
    function </span>click(e) {
        alert(e.target.id);
        e.data = e.data &#124;&#124; 1;
        alert(<span style="color: #a31515">"click function has fired  " </span>+ e.data + <span style="color: #a31515">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue">function </span>clickSon(e) {
        alert(<span style="color: #a31515">"I am son"</span>);
        click(e);
    }
    <span style="color: blue">function </span>clickGrandPa(e) {
        alert(<span style="color: #a31515">"I am GrandPa"</span>);
        click(e);
    }
    $(<span style="color: #a31515">"#panelGrandPa"</span>).bind(<span style="color: #a31515">"click"</span>, clickGrandPa);
    $(<span style="color: #a31515">"#panelSon"</span>).bind(<span style="color: #a31515">"click"</span>, clickSon);
<span style="color: blue">&#60;/</span><span style="color: #a31515">script</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">body</span><span style="color: blue">&#62;
&#60;/</span><span style="color: #a31515">html</span><span style="color: blue">&#62;
</span></pre>
<p><br />这里使用了e.target，不过和之前的非jQuery版本不同，此处的e(event)是调用了jQuery.event.fix(event),也就是说jQuery的处理让event更加透明。不过这段代码的运行还是有问题的，就是click function的fire time 始终为1，也就是说e.data的值无法在多个事件函数里传递，这个我暂时还没有找到原因；不过希望通过进一步探究jQuery源代码找到问题原因及解决思路，本文旨在说明javascript 事件机制 与 jQuery.Bind的简单用法，就此搁笔了，关于前面抛出的问题，也请各位不吝赐教。</p>]]></description>
			<content:encoded><![CDATA[<p>W3C DOM Level2的事件模型规范中，事件在DOM树中的传播过程（从根节点到目标节点）被分为了两个阶段：<a href="http://www.basilwang.net/wp-content/uploads/2011/09/jquerybind1.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="jquerybind" border="0" alt="jquerybind" align="left" src="http://www.basilwang.net/wp-content/uploads/2011/09/jquerybind_thumb1.jpg" width="275" height="263"></a>捕捉（Capture）和冒泡（Bubbling）,而事件在传递的过程中需要先经历Capture Phrase后经历Bubble Phrase 。在firefox下，我们可以用target.addEventListener(type, listener, useCapture),第三个参数指定是否为Capture；但IE不支持捕获，而且jQuery也不支持Capture(不过我觉得Bubbling足够了）。因此后面的讨论主要在Bubbling阶段。首先看一下IE下实现事件模型的代码。</p>
<p>请在IE8运行以下代码(只能在ie8下运行)</p>
<pre class="code"><span style="color: blue">&lt;!</span><span style="color: #a31515">DOCTYPE </span><span style="color: red">html PUBLIC </span><span style="color: blue">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;</span><span style="color: #a31515">html </span><span style="color: red">xmlns</span><span style="color: blue">="http://www.w3.org/1999/xhtml" </span><span style="color: red">lang</span><span style="color: blue">="zh-CN"&gt;
&lt;</span><span style="color: #a31515">head</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">meta </span><span style="color: red">http-equiv</span><span style="color: blue">="Content-Type" </span><span style="color: red">content</span><span style="color: blue">="text/html; charset=utf-8"    /&gt;
&lt;</span><span style="color: #a31515">title</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">title</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">style</span><span style="color: blue">&gt;
     </span><span style="color: #a31515">#panelGrandPa</span>,<span style="color: #a31515">#panelPaPa</span>,<span style="color: #a31515">#panelSon  </span>{ <span style="color: red">border</span>:<span style="color: blue">1px  solid #320213</span>;}
 <span style="color: blue">&lt;/</span><span style="color: #a31515">style</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">head</span><span style="color: blue">&gt;
 &lt;</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelGrandPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">300px</span>;<span style="color: red">height</span>:<span style="color: blue">200px</span>;<span style="color: blue">" &gt;
       &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelPaPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">200px</span>;<span style="color: red">height</span>:<span style="color: blue">100px</span>;<span style="color: blue">" &gt;
            &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelSon" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">100px</span>;<span style="color: red">height</span>:<span style="color: blue">50px</span>;<span style="color: blue">" &gt;

            &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
       &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
    function </span>click() {
        alert(event.srcElement.id);
        event.data = event.data || 1;
        alert(<span style="color: #a31515">"click function has fired  " </span>+ event.data + <span style="color: #a31515">" times"</span>);
        event.data = parseInt(event.data) + 1;
    }
    <span style="color: blue">function </span>clickSon() {
        alert(<span style="color: #a31515">"I am son"</span>);
        click();
    }
    <span style="color: blue">function </span>clickGrandPa() {
        alert(<span style="color: #a31515">"I am GrandPa"</span>);
        click();
    }
    document.getElementById(<span style="color: #a31515">"panelGrandPa"</span>).onclick = clickGrandPa;
    document.getElementById(<span style="color: #a31515">"panelSon"</span>).onclick = clickSon;
<span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">html</span><span style="color: blue">&gt;

</span></pre>
<p>注意传统element.onclick或者element['on'+eventName]，这个是所有浏览器都支持的事件绑定的监听器，但由于上述代码使用了event.srcElement.id，因此只能在IE8下运行。下面看一下在firefox下的使用，这里我们采用了符合W3C DOM的target.addEventListener(type, listener, useCapture)，另外使用了event.target.id。<br />请在firefox,chrome下运行以下代码</p>
<pre class="code"><span style="color: blue">&lt;!</span><span style="color: #a31515">DOCTYPE </span><span style="color: red">html PUBLIC </span><span style="color: blue">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;</span><span style="color: #a31515">html </span><span style="color: red">xmlns</span><span style="color: blue">="http://www.w3.org/1999/xhtml" </span><span style="color: red">lang</span><span style="color: blue">="zh-CN"&gt;
&lt;</span><span style="color: #a31515">head</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">meta </span><span style="color: red">http-equiv</span><span style="color: blue">="Content-Type" </span><span style="color: red">content</span><span style="color: blue">="text/html; charset=utf-8"    /&gt;
&lt;</span><span style="color: #a31515">title</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">title</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">style</span><span style="color: blue">&gt;
     </span><span style="color: #a31515">#panelGrandPa</span>,<span style="color: #a31515">#panelPaPa</span>,<span style="color: #a31515">#panelSon  </span>{ <span style="color: red">border</span>:<span style="color: blue">1px  solid #320213</span>;}
 <span style="color: blue">&lt;/</span><span style="color: #a31515">style</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">head</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelGrandPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">300px</span>;<span style="color: red">height</span>:<span style="color: blue">200px</span>;<span style="color: blue">" &gt;
       &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelPaPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">200px</span>;<span style="color: red">height</span>:<span style="color: blue">100px</span>;<span style="color: blue">" &gt;
            &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelSon" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">100px</span>;<span style="color: red">height</span>:<span style="color: blue">50px</span>;<span style="color: blue">" &gt;

            &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
       &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
    function </span>click(e) {
        alert(e.target.id);
        e.data = e.data || 1;
        alert(<span style="color: #a31515">"click function has fired  " </span>+ e.data + <span style="color: #a31515">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue">function </span>clickSon(e) {
        alert(<span style="color: #a31515">"I am son"</span>);
        click(e);
    }
    <span style="color: blue">function </span>clickGrandPa(e) {
        alert(<span style="color: #a31515">"I am GrandPa"</span>);
        click(e);
    }
    document.getElementById(<span style="color: #a31515">"panelGrandPa"</span>).addEventListener(<span style="color: #a31515">"click"</span>, clickGrandPa, <span style="color: blue">false</span>);
    document.getElementById(<span style="color: #a31515">"panelSon"</span>).addEventListener(<span style="color: #a31515">"click"</span>, clickSon, <span style="color: blue">false</span>);
<span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">html</span><span style="color: blue">&gt;
</span></pre>
<p>那么在jQuery中我们是怎么处理的呢</p>
<pre class="code"><span style="color: blue">&lt;!</span><span style="color: #a31515">DOCTYPE </span><span style="color: red">html PUBLIC </span><span style="color: blue">"-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;</span><span style="color: #a31515">html </span><span style="color: red">xmlns</span><span style="color: blue">="http://www.w3.org/1999/xhtml" </span><span style="color: red">lang</span><span style="color: blue">="zh-CN"&gt;
&lt;</span><span style="color: #a31515">head</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">meta </span><span style="color: red">http-equiv</span><span style="color: blue">="Content-Type" </span><span style="color: red">content</span><span style="color: blue">="text/html; charset=utf-8"    /&gt;
 &lt;</span><span style="color: #a31515">script </span><span style="color: red">type</span><span style="color: blue">="text/javascript" </span><span style="color: red">src</span><span style="color: blue">="http://jqueryjs.googlecode.com/files/jquery-1.3.2.js"&gt;&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">title</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">title</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">style</span><span style="color: blue">&gt;
     </span><span style="color: #a31515">#panelGrandPa</span>,<span style="color: #a31515">#panelPaPa</span>,<span style="color: #a31515">#panelSon  </span>{ <span style="color: red">border</span>:<span style="color: blue">1px  solid #320213</span>;}
 <span style="color: blue">&lt;/</span><span style="color: #a31515">style</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">head</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelGrandPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">300px</span>;<span style="color: red">height</span>:<span style="color: blue">200px</span>;<span style="color: blue">" &gt;
       &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelPaPa" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">200px</span>;<span style="color: red">height</span>:<span style="color: blue">100px</span>;<span style="color: blue">" &gt;
            &lt;</span><span style="color: #a31515">div </span><span style="color: red">id</span><span style="color: blue">="panelSon" </span><span style="color: red">style</span><span style="color: blue">="</span><span style="color: red">width</span>:<span style="color: blue">100px</span>;<span style="color: red">height</span>:<span style="color: blue">50px</span>;<span style="color: blue">" &gt;

            &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
       &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
    function </span>click(e) {
        alert(e.target.id);
        e.data = e.data || 1;
        alert(<span style="color: #a31515">"click function has fired  " </span>+ e.data + <span style="color: #a31515">" times"</span>);
        e.data = parseInt(e.data) + 1;
    }
    <span style="color: blue">function </span>clickSon(e) {
        alert(<span style="color: #a31515">"I am son"</span>);
        click(e);
    }
    <span style="color: blue">function </span>clickGrandPa(e) {
        alert(<span style="color: #a31515">"I am GrandPa"</span>);
        click(e);
    }
    $(<span style="color: #a31515">"#panelGrandPa"</span>).bind(<span style="color: #a31515">"click"</span>, clickGrandPa);
    $(<span style="color: #a31515">"#panelSon"</span>).bind(<span style="color: #a31515">"click"</span>, clickSon);
<span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">html</span><span style="color: blue">&gt;
</span></pre>
<p>这里使用了e.target，不过和之前的非jQuery版本不同，此处的e(event)是调用了jQuery.event.fix(event),也就是说jQuery的处理让event更加透明。不过这段代码的运行还是有问题的，就是click function的fire time 始终为1，也就是说e.data的值无法在多个事件函数里传递，这个我暂时还没有找到原因；不过希望通过进一步探究jQuery源代码找到问题原因及解决思路，本文旨在说明javascript 事件机制 与 jQuery.Bind的简单用法，就此搁笔了，关于前面抛出的问题，也请各位不吝赐教。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2010/05/javascript-event-jquery-bind/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 9.10 Server (Karmic) 迁移Bugzilla</title>
		<link>http://www.basilwang.net/2010/04/ubuntu-9-10-karmic-transfer-bugzilla/</link>
		<comments>http://www.basilwang.net/2010/04/ubuntu-9-10-karmic-transfer-bugzilla/#comments</comments>
		<pubDate>Mon, 05 Apr 2010 09:42:09 +0000</pubDate>
		<dc:creator>basilwang</dc:creator>
				<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://basilwang.gotoip2.com/?p=5</guid>
		<description><![CDATA[<p>项目组去年年底配置了两台服务器，其中的一台安装了Ubuntu 9.10 Server。由于项目组采用Bugzilla作为bug生命周期的管理，需要把Bugzilla迁移了过来。以下记录迁移过程备忘。</p> <p>原服务器 Ubuntu 8.04 Desktop ，&#160; Bugzilla 3.2.2</p> <p>新服务器 Ubuntu 9.10 Server&#160; , --</p> <p>参考网上部分方案，打算采用比较稳妥的方式，形成如下思路</p> <p>1 备份mysql数据库</p> <p>将数据库bugs备份到文件bugsdata.sql<br />$mysqldump bugs &#62; bugsdata.sql<br />再修改bugsdata.sql，在文件头加两行<br />create database if not exists bugs;<br />USE bugs;</p> <p>2 在已安装mysql的9.10Server上恢复数据库</p> <p>此步骤一定在第5步之前，因为Bugzilla的checksetup.pl会自动升级数据库脚本从3.2.2到3.4.4</p> <p>3 打包Bugzilla 文件夹并恢复到Ubuntu 9.10上&#160; （此步骤浏览时报错，忘了具体错误，比较难处理，转到步骤3）</p> <p>4 下载最新Bugzilla 3.4.4, 重新编译。 至于为什么不用ubuntu自带的Bugzilla以及如何下载编译配置Bugzilla，请参见这篇博文<a href="http://www.basilwang.net/2010/01/ubuntu-8-04-install-bugzilla-3-2-2/" target="_blank">Ubuntu 8.04 安装 Bugzilla 3.2.2</a></p> <p>为了防止版本文件夹的变化而修改apache虚拟目录文件，可以创建symbolic link,比如解压后的文件夹为 Bugzilla_3.4.4 可以用 ln –s Bugzilla Bugzilla_3.4.4 创建名为Bugzilla的symbolic link,在apache虚拟目录的配置中可以使用该名称，将来出现新版本只更新Bugzilla的指向即可。</p> <p>5 运行 ./checksetup.pl 的时候，按照提示下载缺少的部分模块，总是有3个模块安装不上</p> <p>Checking perl modules...<br />Checking for DateTime (v0.28) not found<br />Checking for DateTime-TimeZone (v0.71) not found<br />Checking for Template-Toolkit (v2.22) not found</p> <p>解决方法 sudo apt-get install libmysql++-dev&#160; (参考了ubuntuforums.org里一位老兄的帖子<strong><a href="http://ubuntuforums.org/showthread.php?p=8542197" target="_blank">Installing bugzilla and DateTime problem</a>)</strong></p> <p>6 接下来就是按照提示修改Bugzilla的localconfig</p> <p>$webservergroup = ‘www-data’;</p> <p># The DNS name of the host that the database server runs on.<br />$db_host = ‘localhost’;<br /># The name of the database<br />$db_name = ‘bugs’;</p> <p># Who we connect to the database as.</p> <p># The DNS name of the host that the database server runs on.<br />$db_host = ‘localhost’;<br /># The name of the database<br />$db_name = ‘bugs’;</p> <p># Who we connect to the database as.<br />$db_user = ‘bugs’;<br />$db_pass = ‘admin’;<br />注意其中的webservergroup 我设置为了www-data，注意这个是ubuntu的运行apache的用户组（不同于其他linux发行版的apache用户组)</p> <p>7 别忘了在apache下配置该虚拟目录，ubuntu自带的apache可以直接修改的/etc/apache2/sites-enabled下面的文件加入</p> <p>Alias /bugzilla “/var/www/bugzilla″<br />&#60;Directory&#160; “/var/www/bugzilla″&#62;</p> <p>Options +ExecCGI<br />AllowOverride Limit<br />DirectoryIndex index.cgi<br />AddHandler cgi-script .cgi<br />&#60;/Directory&#62;<br />不过我们的服务器使用了自己下载编译的apache2，因为该服务器还做为svn的源代码管理服务器。我在ubuntu 9.10 server 下的apache在启用ssl的时候总是报undefined symbol apr_ldap_ssl_init错误，此处我怀疑可能是ubuntu9.10 server的问题，我在虚拟机ubuntu 8.04 desktop下没有出现此问题。</p> <p>apache2的安装目录更改为/usr/local/apache2，在/usr/local/apache2/conf/httpd.conf中加入上述内容。</p> <p>关于apache2的下载编译以及使用ssl的SVN请浏览<a href="http://www.basilwang.net/2011/09/ubuntu-9-10-ssl-subversion/">Ubuntu 9.10 Server 配置基于SSL的Subversion</a></p> <p>8 sudo /etc/init.d/apache2 restart&#160; (自带的apache2)</p> <p>或者<br />cd /usr/local/apache2/bin&#160; (编译的apache2)<br />sudo ./httpd –k restart</p>]]></description>
			<content:encoded><![CDATA[<p>项目组去年年底配置了两台服务器，其中的一台安装了Ubuntu 9.10 Server。由于项目组采用Bugzilla作为bug生命周期的管理，需要把Bugzilla迁移了过来。以下记录迁移过程备忘。</p>
<p>原服务器 Ubuntu 8.04 Desktop ，&nbsp; Bugzilla 3.2.2</p>
<p>新服务器 Ubuntu 9.10 Server&nbsp; , &#8211;</p>
<p>参考网上部分方案，打算采用比较稳妥的方式，形成如下思路</p>
<p>1 备份mysql数据库</p>
<p>将数据库bugs备份到文件bugsdata.sql<br />$mysqldump bugs &gt; bugsdata.sql<br />再修改bugsdata.sql，在文件头加两行<br />create database if not exists bugs;<br />USE bugs;</p>
<p>2 在已安装mysql的9.10Server上恢复数据库</p>
<p>此步骤一定在第5步之前，因为Bugzilla的checksetup.pl会自动升级数据库脚本从3.2.2到3.4.4</p>
<p>3 打包Bugzilla 文件夹并恢复到Ubuntu 9.10上&nbsp; （此步骤浏览时报错，忘了具体错误，比较难处理，转到步骤3）</p>
<p>4 下载最新Bugzilla 3.4.4, 重新编译。 至于为什么不用ubuntu自带的Bugzilla以及如何下载编译配置Bugzilla，请参见这篇博文<a href="http://www.basilwang.net/2010/01/ubuntu-8-04-install-bugzilla-3-2-2/" target="_blank">Ubuntu 8.04 安装 Bugzilla 3.2.2</a></p>
<p>为了防止版本文件夹的变化而修改apache虚拟目录文件，可以创建symbolic link,比如解压后的文件夹为 Bugzilla_3.4.4 可以用 ln –s Bugzilla Bugzilla_3.4.4 创建名为Bugzilla的symbolic link,在apache虚拟目录的配置中可以使用该名称，将来出现新版本只更新Bugzilla的指向即可。</p>
<p>5 运行 ./checksetup.pl 的时候，按照提示下载缺少的部分模块，总是有3个模块安装不上</p>
<p>Checking perl modules&#8230;<br />Checking for DateTime (v0.28) not found<br />Checking for DateTime-TimeZone (v0.71) not found<br />Checking for Template-Toolkit (v2.22) not found</p>
<p>解决方法 sudo apt-get install libmysql++-dev&nbsp; (参考了ubuntuforums.org里一位老兄的帖子<strong><a href="http://ubuntuforums.org/showthread.php?p=8542197" target="_blank">Installing bugzilla and DateTime problem</a>)</strong></p>
<p>6 接下来就是按照提示修改Bugzilla的localconfig</p>
<p>$webservergroup = ‘www-data’;</p>
<p># The DNS name of the host that the database server runs on.<br />$db_host = ‘localhost’;<br /># The name of the database<br />$db_name = ‘bugs’;</p>
<p># Who we connect to the database as.</p>
<p># The DNS name of the host that the database server runs on.<br />$db_host = ‘localhost’;<br /># The name of the database<br />$db_name = ‘bugs’;</p>
<p># Who we connect to the database as.<br />$db_user = ‘bugs’;<br />$db_pass = ‘admin’;<br />注意其中的webservergroup 我设置为了www-data，注意这个是ubuntu的运行apache的用户组（不同于其他linux发行版的apache用户组)</p>
<p>7 别忘了在apache下配置该虚拟目录，ubuntu自带的apache可以直接修改的/etc/apache2/sites-enabled下面的文件加入</p>
<p>Alias /bugzilla “/var/www/bugzilla″<br />&lt;Directory&nbsp; “/var/www/bugzilla″&gt;</p>
<p>Options +ExecCGI<br />AllowOverride Limit<br />DirectoryIndex index.cgi<br />AddHandler cgi-script .cgi<br />&lt;/Directory&gt;<br />不过我们的服务器使用了自己下载编译的apache2，因为该服务器还做为svn的源代码管理服务器。我在ubuntu 9.10 server 下的apache在启用ssl的时候总是报undefined symbol apr_ldap_ssl_init错误，此处我怀疑可能是ubuntu9.10 server的问题，我在虚拟机ubuntu 8.04 desktop下没有出现此问题。</p>
<p>apache2的安装目录更改为/usr/local/apache2，在/usr/local/apache2/conf/httpd.conf中加入上述内容。</p>
<p>关于apache2的下载编译以及使用ssl的SVN请浏览<a href="http://www.basilwang.net/2011/09/ubuntu-9-10-ssl-subversion/">Ubuntu 9.10 Server 配置基于SSL的Subversion</a></p>
<p>8 sudo /etc/init.d/apache2 restart&nbsp; (自带的apache2)</p>
<p>或者<br />cd /usr/local/apache2/bin&nbsp; (编译的apache2)<br />sudo ./httpd –k restart</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilwang.net/2010/04/ubuntu-9-10-karmic-transfer-bugzilla/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

