﻿<?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>Xixi&#039;s Blog &#187; c/c++</title>
	<atom:link href="http://www.xixis.net/archives/tag/c-cpp/feed" rel="self" type="application/rss+xml" />
	<link>http://www.xixis.net</link>
	<description>http://www.xixis.net  &#124;  Eternal Sunshine of the Spotless Mind</description>
	<lastBuildDate>Thu, 12 Jan 2012 06:04:19 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Facebook性能大提升的秘密：HipHop</title>
		<link>http://www.xixis.net/archives/facebook-large-increase-performance-the-secret-hiphop.html</link>
		<comments>http://www.xixis.net/archives/facebook-large-increase-performance-the-secret-hiphop.html#comments</comments>
		<pubDate>Wed, 10 Mar 2010 13:15:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[c/c++]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[HipHop]]></category>

		<guid isPermaLink="false">http://www.xixis.net/archives/facebook%e6%80%a7%e8%83%bd%e5%a4%a7%e6%8f%90%e5%8d%87%e7%9a%84%e7%a7%98%e5%af%86%ef%bc%9ahiphop.html</guid>
		<description><![CDATA[转自CSDN。
Facebook神秘的PHP项目HipHop for PHP终于揭开面纱。这个项目由一个PHP到C++的转换程序，一个重新实现的PHP运行库，和许多常用PHP扩展的重写版本构成，目的是旨在加速和优化PHP。
用Facebook官方博客（无法直接访问）上项目负责人赵海平（北大1987届遗传与分子生物专业，普林斯顿计算机科学博士）的话说，HipHop项目对Facebook影响巨大。它目前已经支撑了Facebook 90%的Web流量。由于HipHop，Facebook Web服务器上的CPU使用平均减少了50%，从而大大减少了服务器的需求。为了让这一改进也惠及社区，他们决定将之开源，希望能够进一步帮助提高更多大型复杂PHP网站的可伸缩性。

PHP和Facebook的问题
众所周知，Facebook的前端主要是用PHP写的。赵海平说，过去六年Facebook从PHP语言的进展上获益良多。PHP非常简单，易学易用，好读好调试，因此新工程师成长很快，有利地促进了Facebook的更快的创新。
PHP是一种脚本语言，其好处是编程效率高，能够支持产品的快速迭代。但是与传统的编译语言相比，脚本语言的CPU和内存使用效率不好。随着Ajax技术的广泛采用，加上SNS对动态要求较高，这些缺点更显得突出。对于每月超过4000亿次PV的Facebook来说，如何实现扩展，尤其具有挑战性。
常见的办法是直接用C++重写PHP应用中比较复杂的部分，作为PHP扩展。实际上，PHP就转变为一种胶水语言，连接前端HTML和C++应用逻辑。从技术角度讲这也没有问题，但是增加了技能需求，能够在整个应用上工作的工程师数量就大大减少了。学习C++只是编写PHP扩展的第一步，接下来还要理解Zend API。由于Facebook的工程团队较小，每个工程师要支持100万以上的用户。有些代码不是团队里每个人都能看懂，这对于Facebook是无法接受的。
Facebook网站本身的可伸缩性更具挑战性，因为几乎每次页面浏览都是有个性化体验的登录用户发起。浏览主页 时，系统需要查询所有朋友、朋友最重要的状态更新、 根据隐私设置筛选结果，然后还要显示评论、照片等等动态，这一切都需要在一秒内完 成。
自2007年以来，Facebook曾写过几种不同办法解决这些问题。其中包括用另 一种语言重写Facebook，但是由于开发的复杂性和速度等原因，未能实现。他们还重写了PHP的核心部分Zend引擎，并提交给了PHP项目，但最终还是没有获得所需的性能。最后，他们选择了HipHop，终于得偿所愿。
有了HipHop，工程师可以编写代码，用PHP编写组合最后页面的逻辑，并能够继续快速迭代，同时后端服务使用C++, Erlang, Java, Py thon编写，提供新闻提要、搜索、聊天和其他核心功能。
HipHop开发故事
赵海平透露，项目最初是来自几年前Facebook公司一次Hackathon活动（员工在一个晚上自由发挥，实验新的想法），他手工将PHP转换为C++代码，虽然语法上很类似，但是无论是CPU还是内存使用，转换后的C++代码都大大优于PHP。于是他想，如果构建一个系统，编程实现转换，会怎么样呢？
在此之前，已经有了不少改善PHP性能的方法。Zend引擎在运行时转换PHP源代码为运行在Zend虚拟机上的opcode。开源项目APC和eAccelerator将输出缓存，为大多数PHP网站所使用。此外，还有Zend Server这样的商业产品，通过opcode优化和缓存，提高PHP速度。赵海平选择了另一条道路，将PHP直接转为C++，然后再变成本地机器码。当然，有许多开源项目也是同样的思路，Roadsend和phc编译为C，Quercus编译为Java，而Phalanger编译为.NET。
Hackathon之后8个月，赵海平拿出了原型，足以说明这条路可以走通，编译后的代码的确更快。不久，Iain Proctor和Minghui Yang加入进来。接下来又开发了10个月，在生产服务器上测试了6个月。然后正式上线部署，6个月之后，Facebook 90%以上的Web流量都使用了HipHop。
按赵海平的说法，凭借HipHop，Facebook Web服务器上的CPU使用平均减少了50%，从而大大减少了服务器的需求。项目对Facebook影响巨大。为了让这一改进也惠及社区，他们决定将之开源，希望能够进一步帮助提高更多大型复杂PHP网站的可伸缩性。

HipHop的原理
HipHop将PHP代码转换为高度优化的C++代码，然后再用g++编译器编译。它可以保持语义等效地执行源代码，但为了提高性能，牺牲了一些很少用到的特性，比如eval()。
HipHop开发中的主要困难在于，在PHP和C++这两种很不一样的语言之间怎么实现转换。虽然PHP也可以写一些很巧妙的动态特性，但是大多数PHP代码还是非常简单的。if (&#8230;) {&#8230;} else {..} 比foo($x) { include $x; } 肯定更常见。这为性能提高提供了机会。HipHop生成的代码尽可能地使用函数和变量的静态绑定。同时，还使用类型推演来选出变量最可能对应的某个类型，从而节省内存。
转换过程分三步：
1. 静态分析。收集声明关系和依赖关系等信息。
2. 类型推演。选择最合适的类型，是C++的标量？还是String, Array, classes, Object或者Variant。
3. 代码生成。大部分直接将PHP语句和表达式对应为C++的语句和表达式。
在开发过程中，还有一个副产品：HPHPi，是一个实验性的解释器。通过它，不编译PHP源代码也可以运行。它已经用于HipHop自身的调试中。
HipHop在保持了PHP优点的同时，也兼得了C++的性能优势。项目总共有30万行代码，5000多个单元测试。所有这些都将以PHP开源许可证形式发布到GitHub。
更多信息，可以申请加入HipHop的邮件列表：
http://groups.google.com/group/hiphop-php-dev
]]></description>
			<content:encoded><![CDATA[<p>转自CSDN。</p>
<p><a rel="lightbox" href="http://sub.xixis.net/wp-content/uploads/2010/03/clip_image002.jpg"><img style="display: inline; margin-left: 0px; margin-right: 0px; border: 0px;" title="clip_image002" src="http://sub.xixis.net/wp-content/uploads/2010/03/clip_image002_thumb.jpg" border="0" alt="clip_image002" width="134" height="134" align="left" /></a>Facebook神秘的PHP项目HipHop for PHP终于揭开面纱。这个项目由一个PHP到C++的转换程序，一个重新实现的PHP运行库，和许多常用PHP扩展的重写版本构成，目的是旨在加速和优化PHP。</p>
<p>用<a href="http://developers.facebook.com/news.php?story=358blog=1">Facebook官方博客</a>（无法直接访问）上项目负责人赵海平（北大1987届遗传与分子生物专业，普林斯顿计算机科学博士）的话说，<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/hiphop" title="显示HipHop的所有日志" target="_blank">HipHop</a></span>项目对Facebook影响巨大。它目前已经支撑了Facebook 90%的Web流量。由于<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/hiphop" title="显示HipHop的所有日志" target="_blank">HipHop</a></span>，Facebook Web服务器上的CPU使用平均减少了50%，从而大大减少了服务器的需求。为了让这一改进也惠及社区，他们决定将之开源，希望能够进一步帮助提高更多大型复杂PHP网站的可伸缩性。</p>
<p><span id="more-417"></span></p>
<p><a rel="lightbox" href="http://sub.xixis.net/wp-content/uploads/2010/03/clip_image003.jpg"><img style="display: inline; margin-left: 0px; margin-right: 0px; border: 0px;" title="clip_image003" src="http://sub.xixis.net/wp-content/uploads/2010/03/clip_image003_thumb.jpg" border="0" alt="clip_image003" hspace="30" vspace="30" width="208" height="208" align="right" /></a><strong>PHP</strong><strong>和</strong><strong>Facebook</strong><strong>的问题</strong></p>
<p>众所周知，Facebook的前端主要是用PHP写的。赵海平说，过去六年Facebook从PHP语言的进展上获益良多。PHP非常简单，易学易用，好读好调试，因此新工程师成长很快，有利地促进了Facebook的更快的创新。</p>
<p>PHP是一种脚本语言，其好处是编程效率高，能够支持产品的快速迭代。但是与传统的编译语言相比，脚本语言的CPU和内存使用效率不好。随着Ajax技术的广泛采用，加上SNS对动态要求较高，这些缺点更显得突出。对于每月超过4000亿次PV的Facebook来说，如何实现扩展，尤其具有挑战性。</p>
<p>常见的办法是直接用C++重写PHP应用中比较复杂的部分，作为PHP扩展。实际上，PHP就转变为一种胶水语言，连接前端HTML和C++应用逻辑。从技术角度讲这也没有问题，但是增加了技能需求，能够在整个应用上工作的工程师数量就大大减少了。学习C++只是编写PHP扩展的第一步，接下来还要理解Zend API。由于Facebook的工程团队较小，每个工程师要支持100万以上的用户。有些代码不是团队里每个人都能看懂，这对于Facebook是无法接受的。</p>
<p>Facebook网站本身的可伸缩性更具挑战性，因为几乎每次页面浏览都是有个性化体验的登录用户发起。浏览主页 时，系统需要查询所有朋友、朋友最重要的状态更新、 根据隐私设置筛选结果，然后还要显示评论、照片等等动态，这一切都需要在一秒内完 成。</p>
<p>自2007年以来，Facebook曾写过几种不同办法解决这些问题。其中包括用另 一种语言重写Facebook，但是由于开发的复杂性和速度等原因，未能实现。他们还重写了PHP的核心部分Zend引擎，并提交给了PHP项目，但最终还是没有获得所需的性能。最后，他们选择了<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/hiphop" title="显示HipHop的所有日志" target="_blank">HipHop</a></span>，终于得偿所愿。</p>
<p>有了HipHop，工程师可以编写代码，用PHP编写组合最后页面的逻辑，并能够继续快速迭代，同时后端服务使用C++, Erlang, Java, Py thon编写，提供新闻提要、搜索、聊天和其他核心功能。</p>
<p><strong>HipHop</strong><strong>开发故事</strong></p>
<p>赵海平透露，项目最初是来自几年前Facebook公司一次Hackathon活动（员工在一个晚上自由发挥，实验新的想法），他手工将PHP转换为C++代码，虽然语法上很类似，但是无论是CPU还是内存使用，转换后的C++代码都大大优于PHP。于是他想，如果构建一个系统，编程实现转换，会怎么样呢？</p>
<p>在此之前，已经有了不少改善PHP性能的方法。Zend引擎在运行时转换PHP源代码为运行在Zend虚拟机上的opcode。开源项目APC和eAccelerator将输出缓存，为大多数PHP网站所使用。此外，还有Zend Server这样的商业产品，通过opcode优化和缓存，提高PHP速度。赵海平选择了另一条道路，将PHP直接转为C++，然后再变成本地机器码。当然，有许多开源项目也是同样的思路，Roadsend和phc编译为C，Quercus编译为Java，而Phalanger编译为.NET。</p>
<p>Hackathon之后8个月，赵海平拿出了原型，足以说明这条路可以走通，编译后的代码的确更快。不久，Iain Proctor和Minghui Yang加入进来。接下来又开发了10个月，在生产服务器上测试了6个月。然后正式上线部署，6个月之后，Facebook 90%以上的Web流量都使用了HipHop。</p>
<p>按赵海平的说法，凭借HipHop，Facebook Web服务器上的CPU使用平均减少了50%，从而大大减少了服务器的需求。项目对Facebook影响巨大。为了让这一改进也惠及社区，他们决定将之开源，希望能够进一步帮助提高更多大型复杂PHP网站的可伸缩性。</p>
<p><a rel="lightbox" href="http://sub.xixis.net/wp-content/uploads/2010/03/clip_image005.jpg"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;" title="clip_image005" src="http://sub.xixis.net/wp-content/uploads/2010/03/clip_image005_thumb.jpg" border="0" alt="clip_image005" width="490" height="331" /></a></p>
<p><strong>HipHop</strong><strong>的原理</strong></p>
<p>HipHop将PHP代码转换为高度优化的C++代码，然后再用g++编译器编译。它可以保持语义等效地执行源代码，但为了提高性能，牺牲了一些很少用到的特性，比如eval()。</p>
<p>HipHop开发中的主要困难在于，在PHP和C++这两种很不一样的语言之间怎么实现转换。虽然PHP也可以写一些很巧妙的动态特性，但是大多数PHP代码还是非常简单的。if (&#8230;) {&#8230;} else {..} 比foo($x) { include $x; } 肯定更常见。这为性能提高提供了机会。HipHop生成的代码尽可能地使用函数和变量的静态绑定。同时，还使用类型推演来选出变量最可能对应的某个类型，从而节省内存。</p>
<p>转换过程分三步：</p>
<p>1. 静态分析。收集声明关系和依赖关系等信息。</p>
<p>2. 类型推演。选择最合适的类型，是C++的标量？还是String, Array, classes, Object或者Variant。</p>
<p>3. 代码生成。大部分直接将PHP语句和表达式对应为C++的语句和表达式。</p>
<p>在开发过程中，还有一个副产品：HPHPi，是一个实验性的解释器。通过它，不编译PHP源代码也可以运行。它已经用于HipHop自身的调试中。</p>
<p>HipHop在保持了PHP优点的同时，也兼得了C++的性能优势。项目总共有30万行代码，5000多个单元测试。所有这些都将以PHP开源许可证形式发布到GitHub。</p>
<p>更多信息，可以申请加入HipHop的邮件列表：</p>
<p><a href="http://groups.google.com/group/hiphop-php-dev">http://groups.google.com/group/hiphop-php-dev</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.xixis.net/archives/facebook-large-increase-performance-the-secret-hiphop.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C语言常类型 const</title>
		<link>http://www.xixis.net/archives/c-type-const-chang.html</link>
		<comments>http://www.xixis.net/archives/c-type-const-chang.html#comments</comments>
		<pubDate>Wed, 10 Feb 2010 19:46:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[c/c++]]></category>
		<category><![CDATA[const]]></category>
		<category><![CDATA[常类型]]></category>

		<guid isPermaLink="false">http://www.xixis.net/develop/c-cpp/c%e8%af%ad%e8%a8%80%e5%b8%b8%e7%b1%bb%e5%9e%8b-const/</guid>
		<description><![CDATA[ 基本解释 const是一个C语言的关键字，它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性，另外，在观看别人代码的时候，清晰理解const所起的作用，对理解对方的程序也有一些帮助。 虽然这听起来很简单，但实际上，const的使用也是c语言中一个比较微妙的地方，微妙在何处呢？请看下面几个问题。  问题：const变量 &#038; 常量  为什么我象下面的例子一样用一个const变量来初始化数组，ANSI C的编译器会报告一个错误呢？ 

const int n = 5;
int a&#91;n&#93;;


答案与分析:

　  1）、这个问题讨论的是“常量”与“只读变量”的区别。常量肯定是只读的，例如5， “abc”，等，肯定是只读的，因为程序中根本没有地方存放它的值，当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值，只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符（Qualifier）。上述代码中变量n被修饰为只读变量，可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是“常量”，“只读变量”也是不可以的。

2)、注意：在ANSI C中，这种写法是错误的，因为数组的大小应该是个常量，而const int n,n只是一个变量（常量 != 不可变的变量，但在标准C++中，这样定义的是一个常量，这种写法是对的），实际上，根据编译过程及内存分配来看，这种用法本来就应该是合理的，只是 ANSI C对数组的规定限制了它。

3)、那么，在ANSI C 语言中用什么来定义常量呢？答案是enum类型和#define宏，这两个都可以用来定义常量。 

问题：const变量 &#038; const 限定的内容

下面的代码编译器会报一个错误，请问，哪一个语句是错误的呢？

typedef char * pStr;
char string&#91;4&#93; = &#34;abc&#34;;
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;


答案与分析：

问题出在p2++ 上。

　　1)、const使用的基本形式： const char m; 

　　限定m不可变。

　　2)、替换1式中的 m, const char *pm; 

　　限定*pm不可变，当然pm是可变的，因此问题中p1++是对的。

　　3)、替换1式char, const newType m; 

　　限定m不可变，问题中的charptr就是一种新类型，因此问题中p2不可变，p2++是错误的。

问题：const变量 &#038; 字符串常量

请问下面的代码有什么问题？


char *p = &#34;i'm hungry!&#34;;
p&#91;0&#93;= 'I';


答案与分析：

上面的代码可能会造成内存的非法写操作。分析如下， “i&#8217;m hungry”实质上是字符串常量，而常量往往被编译器放在只读的内存区，不可写。p初始指向这个只读的内存区，而 p[0] = &#8216;I&#8217;则企图去写这个地方，编译器当然不会答应。

问题：const变量 &#038; 字符串常量2

　　请问char a[3] = &#8220;abc&#8221; 合法吗？使用它有什么隐患？ 

答案与分析：

在标准C中这是合法的，但是它的生存环境非常狭小；它定义一个大小为3的数组，初始化为“abc”，，注意，它没有通常的字符串终止符&#8217;&#92;0&#8242;，因此这个数组只是看起来像C语言中的字符串，实质上却不是，因此所有对字符串进行处理的函数，比如strcpy、printf等，都不能够被使用在这个假字符串上。

问题5：const &#038; 指针

类型声明中const用来修饰一个常量，有如下两种写法，那么，请问，下面分别用const限定不可变的内容是什么?

1)、const在前面

const int nValue； //nValue是const
const char *pContent; //*pContent是const, pContent可变
const ...]]></description>
			<content:encoded><![CDATA[<p><strong> 基本解释</strong> <span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/const" title="显示const的所有日志" target="_blank">const</a></span>是一个C语言的关键字，它限定一个变量不允许被改变。使用<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/const" title="显示const的所有日志" target="_blank">const</a></span>在一定程度上可以提高程序的健壮性，另外，在观看别人代码的时候，清晰理解<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/const" title="显示const的所有日志" target="_blank">const</a></span>所起的作用，对理解对方的程序也有一些帮助。<br /> 虽然这听起来很简单，但实际上，const的使用也是c语言中一个比较微妙的地方，微妙在何处呢？请看下面几个问题。<br /> <span id="more-368"></span> <strong>问题：const变量 &#038; 常量</strong><br />  为什么我象下面的例子一样用一个const变量来初始化数组，ANSI C的编译器会报告一个错误呢？<br /> </p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> n <span style="color: #000080;">=</span> <span style="color: #0000dd;">5</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span> a<span style="color: #008000;">&#91;</span>n<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span></pre></div></div>

<p><br />
答案与分析:<br />
<br />
　  1）、这个问题讨论的是“常量”与“只读变量”的区别。常量肯定是只读的，例如5， “abc”，等，肯定是只读的，因为程序中根本没有地方存放它的值，当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值，只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符（Qualifier）。上述代码中变量n被修饰为只读变量，可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是“常量”，“只读变量”也是不可以的。<br />
<br />
2)、注意：在ANSI C中，这种写法是错误的，因为数组的大小应该是个常量，而const int n,n只是一个变量（常量 != 不可变的变量，但在标准C++中，这样定义的是一个常量，这种写法是对的），实际上，根据编译过程及内存分配来看，这种用法本来就应该是合理的，只是 ANSI C对数组的规定限制了它。<br />
<br />
3)、那么，在ANSI C 语言中用什么来定义常量呢？答案是enum类型和#define宏，这两个都可以用来定义常量。 <br />
<br />
<strong>问题：const变量 &#038; const 限定的内容</strong><br />
<br />
下面的代码编译器会报一个错误，请问，哪一个语句是错误的呢？<br /></p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> pStr<span style="color: #008080;">;</span>
<span style="color: #0000ff;">char</span> string<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;abc&quot;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>p1 <span style="color: #000080;">=</span> string<span style="color: #008080;">;</span>
<span style="color: #0000ff;">const</span> pStr p2 <span style="color: #000080;">=</span> string<span style="color: #008080;">;</span>
p1<span style="color: #000040;">++</span><span style="color: #008080;">;</span>
p2<span style="color: #000040;">++</span><span style="color: #008080;">;</span></pre></div></div>

<p><br />
答案与分析：<br />
<br />
问题出在p2++ 上。<br />
<br />
　　1)、const使用的基本形式： const char m; <br />
<br />
　　限定m不可变。<br />
<br />
　　2)、替换1式中的 m, const char *pm; <br />
<br />
　　限定*pm不可变，当然pm是可变的，因此问题中p1++是对的。<br />
<br />
　　3)、替换1式char, const newType m; <br />
<br />
　　限定m不可变，问题中的charptr就是一种新类型，因此问题中p2不可变，p2++是错误的。<br />
<br />
问题：const变量 &#038; 字符串常量<br />
<br />
请问下面的代码有什么问题？<br />
<br /></p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>p <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;i'm hungry!&quot;</span><span style="color: #008080;">;</span>
p<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #000080;">=</span> <span style="color: #FF0000;">'I'</span><span style="color: #008080;">;</span></pre></div></div>

<p><br />
答案与分析：<br />
<br />
上面的代码可能会造成内存的非法写操作。分析如下， “i&#8217;m hungry”实质上是字符串常量，而常量往往被编译器放在只读的内存区，不可写。p初始指向这个只读的内存区，而 p[0] = &#8216;I&#8217;则企图去写这个地方，编译器当然不会答应。<br />
<br />
问题：const变量 &#038; 字符串常量2<br />
<br />
　　请问char a[3] = &#8220;abc&#8221; 合法吗？使用它有什么隐患？ <br />
<br />
答案与分析：<br />
<br />
在标准C中这是合法的，但是它的生存环境非常狭小；它定义一个大小为3的数组，初始化为“abc”，，注意，它没有通常的字符串终止符&#8217;&#92;0&#8242;，因此这个数组只是看起来像C语言中的字符串，实质上却不是，因此所有对字符串进行处理的函数，比如strcpy、printf等，都不能够被使用在这个假字符串上。<br />
<br />
问题5：const &#038; 指针<br />
<br />
类型声明中const用来修饰一个常量，有如下两种写法，那么，请问，下面分别用const限定不可变的内容是什么?<br />
<br />
1)、const在前面</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> nValue； <span style="color: #666666;">//nValue是const</span>
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>pContent<span style="color: #008080;">;</span> <span style="color: #666666;">//*pContent是const, pContent可变</span>
<span style="color: #0000ff;">const</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> pContent<span style="color: #008080;">;</span><span style="color: #666666;">//pContent是const,*pContent可变</span>
<span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> pContent<span style="color: #008080;">;</span> <span style="color: #666666;">//pContent是const,*pContent可变</span>
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> pContent<span style="color: #008080;">;</span> <span style="color: #666666;">//pContent和*pContent都是const</span></pre></div></div>

<p><br />
2)、const在后面，与上面的声明对等<br />
<br />int const nValue； // nValue是const</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">char</span> <span style="color: #0000ff;">const</span> <span style="color: #000040;">*</span> pContent<span style="color: #008080;">;</span><span style="color: #666666;">// *pContent是const, pContent可变</span>
<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> pContent<span style="color: #008080;">;</span><span style="color: #666666;">//pContent是const,*pContent可变</span>
<span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> pContent<span style="color: #008080;">;</span><span style="color: #666666;">// pContent是const,*pContent可变</span>
<span style="color: #0000ff;">char</span> <span style="color: #0000ff;">const</span><span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> pContent<span style="color: #008080;">;</span><span style="color: #666666;">// pContent和*pContent都是const</span></pre></div></div>

<p><br />
<br />
答案与分析：<br />
<br />const和指针一起使用是C语言中一个很常见的困惑之处，在实际开发中，特别是在看别人代码的时候，常常会因为这样而不好判断作者的意图，下面讲一下我的判断原则：<br />
<br />
沿着*号划一条线，如果const位于*的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；如果const位于*的右侧，const就是修饰指针本身，即指针本身是常量。你可以根据这个规则来看上面声明的实际意义，相信定会一目了然。<br />
<br />
另外，需要注意：对于const (char *) ; 因为char *是一个整体，相当于一个类型(如 char)，因此，这是限定指针是const。<br />
<br />
<br />
 另＝＝＝＝＝＝＝<br />
<br />
const用于函数时出现三个位置:<br />
例如:<br />
</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">const</span> returnVal function <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> list_array<span style="color: #008000;">&#41;</span><span style="color: #0000ff;">const</span><span style="color: #008080;">;</span></pre></div></div>

<p><br />
形式不过如此</p>
<blockquote><p>
第一个const意思是:返回值是常量<br />
第二个const意思是:函数过程中不能修改list_array的值<br />
第三个 const意思是:函数过程不能隐式的修改function参数的值
</p></blockquote>
<p><br />
＝＝＝<br /><br />
const char*, char const*, char*const的区别问题几乎是C++面试中每次都会有的题目。<br /> <br />
事实上这个概念谁都有只是三种声明方式非常相似很容易记混。 <br />
Bjarne在他的The C++ Programming Language里面给出过一个助记的方法： <br />
把一个声明从右向左读。</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> cp<span style="color: #008080;">;</span> <span style="color: #008000;">&#40;</span> <span style="color: #000040;">*</span> 读成 pointer to <span style="color: #008000;">&#41;</span> 
cp is a <span style="color: #0000ff;">const</span> pointer to <span style="color: #0000ff;">char</span> 
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> p<span style="color: #008080;">;</span> 
p is a pointer to <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #008080;">;</span> 
<span style="color: #0000ff;">char</span> <span style="color: #0000ff;">const</span> <span style="color: #000040;">*</span> p<span style="color: #008080;">;</span></pre></div></div>

<p>同上因为C++里面没有const*的运算符，所以const只能属于前面的类型。 <br />
<br />
<br />
另:下面定义的一个指向字符串的常量指针： <br />
　　</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> <span style="color: #0000ff;">const</span> prt1 <span style="color: #000080;">=</span> stringprt1<span style="color: #008080;">;</span></pre></div></div>

<p>　　其中，ptr1是一个常量指针。因此，下面赋值是非法的。<br />
　　</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">ptr1 <span style="color: #000080;">=</span> stringprt2<span style="color: #008080;">;</span></pre></div></div>

<p>　　而下面的赋值是合法的：<br />
　　</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #000040;">*</span>ptr1 <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;m&quot;</span><span style="color: #008080;">;</span></pre></div></div>

<p>　　因为指针ptr1所指向的变量是可以更新的，不可更新的是常量指针ptr1所指的方向(别的字符串)。<br />
　　下面定义了一个指向字符串常量的指针：<br />
　　</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">const</span> <span style="color: #000040;">*</span> ptr2 <span style="color: #000080;">=</span> stringprt1<span style="color: #008080;">;</span></pre></div></div>

<p>　　其中，ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的，而ptr2是可以更新的。因此，<br />
　　</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #000040;">*</span>ptr2 <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;x&quot;</span><span style="color: #008080;">;</span></pre></div></div>

<p>　　是非法的，而：<br />
　　</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">ptr2 <span style="color: #000080;">=</span> stringptr2<span style="color: #008080;">;</span></pre></div></div>

<p>　　是合法的。 <br />
　　所以，在使用const修饰指针时，应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时，const修饰符的位置不同，前者const放在*和指针名之间，后者const放在类型说明符前。 </p>
]]></content:encoded>
			<wfw:commentRss>http://www.xixis.net/archives/c-type-const-chang.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>c++ 字符串处理函数</title>
		<link>http://www.xixis.net/archives/c-string-processing-functions.html</link>
		<comments>http://www.xixis.net/archives/c-string-processing-functions.html#comments</comments>
		<pubDate>Wed, 10 Feb 2010 19:36:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[c/c++]]></category>
		<category><![CDATA[string]]></category>
		<category><![CDATA[字符串]]></category>

		<guid isPermaLink="false">http://www.xixis.net/develop/c-cpp/c-%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%a4%84%e7%90%86%e5%87%bd%e6%95%b0/</guid>
		<description><![CDATA[
strcpy&#40;char destination&#91;&#93;, const char source&#91;&#93;&#41;;

strcpy：将字符串source拷贝到字符串destination 中。
strcpy函数应用举例
原型：

strcpy&#40;char destination&#91;&#93;, const char source&#91;&#93;&#41;;

功能：将字符串source拷贝到字符串destination中

例程：

 #include &#60;iostream.h&#62;
#include &#60;string.h&#62;
void main&#40;void&#41;
&#123;
　char str1&#91;10&#93; = &#123;&#34;TsinghuaOK&#34;&#125;;
　char str2&#91;10&#93; = &#123;&#34;Computer&#34;&#125;;
　 cout&#60;&#60;strcpy&#40;str1,str2&#41;&#60;&#60;endl;
&#125;

运行结果是:Computer
第二个字符串将覆盖掉第一个字符串的所有内容！

注意：在定义数组时，字符数组1的字符串长度必须大于或等于字符串2的字符串长度。不能用赋值语句将一个字符串常量或字符数组直接赋给一个字符数组。所有字符串处理函数都包含在头文件string.h中。



strncpy&#40;char destination&#91;&#93;, const char source&#91;&#93;, int numchars&#41;;

strncpy：将字符串source中前numchars个字符拷贝到字符串 destination中。
strncpy函数应用举例
原型：

strncpy&#40;char destination&#91;&#93;, const char source&#91;&#93;, int numchars&#41;;

功能：将字符串source中前numchars个字符拷贝到字符串destination中例程：

#include &#60;iostream.h&#62;
#include &#60;string.h&#62;
void main&#40;void&#41;
&#123;
　char str1&#91;10&#93; = &#123;&#34;Tsinghua &#34;&#125;;
　char str2&#91;10&#93; = &#123;&#34;Computer&#34;&#125;;
　 cout&#60;&#60;strncpy&#40;str1,str2,3&#41;&#60;&#60;endl;
&#125;

运行结果：Comnghua

注意：字符串source中前 numchars个字符将覆盖掉字符串destination中前numchars个字符！



strcat&#40;char target&#91;&#93;, const char source&#91;&#93;&#41;;

strcat: 将字符串source接到字符串target的后面。
strcat函数应用举例
原型：

strcat&#40;char target&#91;&#93;, const char source&#91;&#93;&#41;;

功能：将字符串source接到字符串target的后面
例程：

#include &#60;iostream.h&#62;
#include &#60;string.h&#62;
void main&#40;void&#41;
&#123;
　char str1&#91;&#93; = &#123;&#34;Tsinghua &#34;&#125;;
　char str2&#91;&#93; = &#123;&#34;Computer&#34;&#125;;
　 cout&#60;&#60;strcpy&#40;str1,str2&#41;&#60;&#60;endl;
&#125;

运行结果：Tsinghua Computer

注意：在定义字符数组1的长度时应该考虑字符数组2的长度，因为连接后新字符串的长度为两个字符串长度之和。进行字符串连接后，字符串1的结尾符将自动被去掉，在结尾串末尾保留新字符串后面一个结尾符。



strncat&#40;char target&#91;&#93;, const char source&#91;&#93;, int numchars&#41;;

strncat:将字符串source的前numchars个字符接到字符串 target的后面。
strncat函数应用举例：
原型：

strncat&#40;char target&#91;&#93;, const char source&#91;&#93;, int numchars&#41;;

功能：将字符串source的前numchars个字符接到字符串target的后面
 例程：

#include &#60;iostream.h&#62;
#include &#60;string.h&#62;
void main&#40;void&#41;
&#123;
　char str1&#91;&#93; = &#123;&#34;Tsinghua &#34;&#125;;
　char str2&#91;&#93; = ...]]></description>
			<content:encoded><![CDATA[
<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strcpy</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> destination<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>strcpy：将<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/%e5%ad%97%e7%ac%a6%e4%b8%b2" title="显示字符串的所有日志" target="_blank">字符串</a></span>source拷贝到<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/%e5%ad%97%e7%ac%a6%e4%b8%b2" title="显示字符串的所有日志" target="_blank">字符串</a></span>destination 中。<br />
<strong>strcpy函数应用举例</strong><br />
原型：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strcpy</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> destination<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>功能：将字符串source拷贝到字符串destination中<br />
<span id="more-367"></span><br />
例程：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"> <span style="color: #339900;">#include &lt;iostream.h&gt;</span>
<span style="color: #339900;">#include &lt;<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/string" title="显示string的所有日志" target="_blank">string</a></span>.h&gt;</span>
<span style="color: #0000ff;">void</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
　<span style="color: #0000ff;">char</span> str1<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;TsinghuaOK&quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">char</span> str2<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;Computer&quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　 <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">strcpy</span><span style="color: #008000;">&#40;</span>str1,str2<span style="color: #008000;">&#41;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>运行结果是:Computer</p>
<p>第二个字符串将覆盖掉第一个字符串的所有内容！</p>
<blockquote>
<p>注意：在定义数组时，字符数组1的字符串长度必须大于或等于字符串2的字符串长度。不能用赋值语句将一个字符串常量或字符数组直接赋给一个字符数组。所有字符串处理函数都包含在头文件<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/string" title="显示string的所有日志" target="_blank">string</a></span>.h中。
</p></blockquote>
<p></p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strncpy</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> destination<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> numchars<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>strncpy：将字符串source中前numchars个字符拷贝到字符串 destination中。<br />
strncpy函数应用举例<br />
原型：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strncpy</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> destination<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> numchars<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>功能：将字符串source中前numchars个字符拷贝到字符串destination中<br />例程：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream.h&gt;</span>
<span style="color: #339900;">#include &lt;string.h&gt;</span>
<span style="color: #0000ff;">void</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
　<span style="color: #0000ff;">char</span> str1<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;Tsinghua &quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">char</span> str2<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;Computer&quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　 <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">strncpy</span><span style="color: #008000;">&#40;</span>str1,str2,<span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>运行结果：Comnghua</p>
<blockquote><p>
注意：字符串source中前 numchars个字符将覆盖掉字符串destination中前numchars个字符！
</p></blockquote>
<p></p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strcat</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> target<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>strcat: 将字符串source接到字符串target的后面。<br />
strcat函数应用举例<br />
原型：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strcat</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> target<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>功能：将字符串source接到字符串target的后面<br />
例程：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream.h&gt;</span>
<span style="color: #339900;">#include &lt;string.h&gt;</span>
<span style="color: #0000ff;">void</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
　<span style="color: #0000ff;">char</span> str1<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;Tsinghua &quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">char</span> str2<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;Computer&quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　 <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">strcpy</span><span style="color: #008000;">&#40;</span>str1,str2<span style="color: #008000;">&#41;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>运行结果：Tsinghua Computer</p>
<blockquote><p>
注意：在定义字符数组1的长度时应该考虑字符数组2的长度，因为连接后新字符串的长度为两个字符串长度之和。进行字符串连接后，字符串1的结尾符将自动被去掉，在结尾串末尾保留新字符串后面一个结尾符。
</p></blockquote>
<p></p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strncat</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> target<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> numchars<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>strncat:将字符串source的前numchars个字符接到字符串 target的后面。<br />
strncat函数应用举例：<br />
原型：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strncat</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> target<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> source<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">int</span> numchars<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>功能：将字符串source的前numchars个字符接到字符串target的后面<br />
 例程：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream.h&gt;</span>
<span style="color: #339900;">#include &lt;string.h&gt;</span>
<span style="color: #0000ff;">void</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
　<span style="color: #0000ff;">char</span> str1<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;Tsinghua &quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">char</span> str2<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #FF0000;">&quot;Computer&quot;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
　 <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">strncat</span><span style="color: #008000;">&#40;</span>str1,str2,<span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>运行结果：Tsinghua Com</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> <span style="color: #0000dd;">strcmp</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> firststring<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> secondstring<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>strcmp：比较两个字符串firststring和 secondstring。<br />
strcmp函数应用举例<br />
原型：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> <span style="color: #0000dd;">strcmp</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> firststring<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> secondstring<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>功能：比较两个字符串firststring和secondstring<br />
例程： </p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream.h&gt;</span>
<span style="color: #339900;">#include &lt;string.h&gt;</span>
<span style="color: #0000ff;">void</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
　<span style="color: #0000ff;">char</span> buf1<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;aaa&quot;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">char</span> buf2<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;bbb&quot;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">char</span> buf3<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;ccc&quot;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">int</span> ptr<span style="color: #008080;">;</span>
　ptr <span style="color: #000080;">=</span> <span style="color: #0000dd;">strcmp</span><span style="color: #008000;">&#40;</span>buf2,buf1<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>ptr <span style="color: #000080;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>
　　<span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;Buffer 2 is greater than buffer 1&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
　<span style="color: #0000ff;">else</span>
　　<span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;Buffer 2 is less than buffer 1&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
　ptr <span style="color: #000080;">=</span> <span style="color: #0000dd;">strcmp</span><span style="color: #008000;">&#40;</span>buf2,buf3<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
　<span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>ptr <span style="color: #000080;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>
　　<span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;Buffer 2 is greater than buffer 3&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
　<span style="color: #0000ff;">else</span>
　　<span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;Buffer 2 is less than buffer 3&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>运行结果是:Buffer 2 is less than buffer 1 <br />
                 Buffer 2 is greater than buffer 3</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strlen</span><span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> string<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>strlen：统计字符串string中字符的个数。　　<br />
strlen函数应用举例<br />
原型：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000dd;">strlen</span><span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> string<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>功能：统计字符串string中字符的个数<br />
例程：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream.h&gt;</span>
<span style="color: #339900;">#include &lt;string.h&gt;</span>
<span style="color: #0000ff;">void</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
  <span style="color: #0000ff;">char</span> str<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">100</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
  <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;请输入一个字符串:&quot;</span><span style="color: #008080;">;</span>
  <span style="color: #0000dd;">cin</span><span style="color: #000080;">&gt;&gt;</span>str<span style="color: #008080;">;</span>
  <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;The length of the string is :&quot;</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">strlen</span><span style="color: #008000;">&#40;</span>str<span style="color: #008000;">&#41;</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;个&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>运行结果The length of the string is x (x为你输入的字符总数字)</p>
<blockquote><p>
注意：strlen函数的功能是计算字符串的实际长度，不包括&#8217;&#92;0&#8242;在内。另外，strlen函数也可以直接测试字符串常量的长度，如：strlen(&#8220;Welcome &#8220;)。
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.xixis.net/archives/c-string-processing-functions.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++常类型(const)</title>
		<link>http://www.xixis.net/archives/c-regular-type-const.html</link>
		<comments>http://www.xixis.net/archives/c-regular-type-const.html#comments</comments>
		<pubDate>Thu, 29 Nov 2007 13:19:49 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[c/c++]]></category>
		<category><![CDATA[数据类型]]></category>

		<guid isPermaLink="false">http://127.0.0.1/wp7/?p=65</guid>
		<description><![CDATA[常类型是指使用类型修饰符const说明的类型，常类型的变量或对象的值是不能被更新的。因此，定义或说明常类型时必须进行初始化。　　一般常量和对象常量　　1. 一般常量　　一般常量是指简单类型的常量。这种常量在定义时，修饰符const可以用在类型说明符前，也可以用在类型说明符后。如：　　int const x=2;　　或　　const int x=2;　　定义或说明一个常数组可采用如下格式：　　  const []…　　或者 　　const  []…　　例如：　　int const a[5]={1, 2, 3, 4, 5};　　2. 常对象　　常对象是指对象常量，定义格式如下：　　< 类名> const 　　或者　　const  　　定义常对象时，同样要进行初始化，并且该对象不能再被更新，修饰符const可以放在类名后面，也可以放在类名前面。　　常指针和常引用　　1. 常指针　　使用const修饰指针时，由于const的位置不同，而含意不同。下面举两个例子，说明它们的区别。　　下面定义的一个指向字符串的常量指针：　　 char * const prt1 = stringprt1;　　其中，ptr1是一个常量指针。因此，下面赋值是非法的。　　ptr1 = stringprt2;　　而下面的赋值是合法的：　　 *ptr1 = &#8220;m&#8221;;　　因为指针ptr1所指向的变量是可以更新的，不可更新的是常量指针ptr1所指的方向(别的字符串)。　　下面定义了一个指向字符串常量的指针：　　 const * ptr2 = stringprt1;　　其中，ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的，而ptr2是可以更新的。因此，　　*ptr2 = &#8220;x&#8221;;　　是非法的，而：　　ptr2 = stringptr2;　　是合法的。　　所以，在使用 const修饰指针时，应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时，const修饰符的位置不同，前者 const放在*和指针名之间，后者const放在类型说明符前。　　2. 常引用　　使用const修饰符也可以说明引用，被说明的引用为常引用，该引用所引用的对象不能被更新。其定义格式如下：　　const  &#038; 　　例如：　　const double & v;　　在实际应用中，常指针和常引用往往用来作函数的形参，这样的参数称为常参数。　　在C++面向对象的程序设计中，指针和引用使用得较多，其中使用const修饰的常指针和常引用用得更多。使用常参数则表明该函数不会更新某个参数所指向或所引用的对象，这样，在参数传递过程中就不需要执行拷贝初始化构造函数，这将会改善程序的运行效率。　　下面举一例子说明常指针作函数参数的作法。
#include "iostream.h"const int N = 6;void print(const int *p, int n);int main(){ &#160; &#160;int array[N]; &#160; &#160;for (int i=0; i ]]></description>
			<content:encoded><![CDATA[<p>常类型是指使用类型修饰符const说明的类型，常类型的变量或对象的值是不能被更新的。因此，定义或说明常类型时必须进行初始化。<br/><span id="more-65"></span><br/>　　一般常量和对象常量<br/><br/>　　1. 一般常量<br/><br/>　　一般常量是指简单类型的常量。这种常量在定义时，修饰符const可以用在类型说明符前，也可以用在类型说明符后。如：<br/><br/>　　int const x=2;<br/><br/>　　或<br/><br/>　　const int x=2;<br/><br/>　　定义或说明一个常数组可采用如下格式：<br/><br/>　　 <类型说明符> const <数组名>[<大小>]…<br/><br/>　　或者<br/><br/> 　　const <类型说明符> <数组名>[<大小>]…<br/><br/>　　例如：<br/><br />　　int const a[5]={1, 2, 3, 4, 5};<br/><br/>　　2. 常对象<br/><br/>　　常对象是指对象常量，定义格式如下：<br/><br/>　　< 类名> const <对象名><br/><br/>　　或者<br/><br/>　　const <类名> <对象名><br/><br/>　　定义常对象时，同样要进行初始化，并且该对象不能再被更新，修饰符const可以放在类名后面，也可以放在类名前面。<br/><br/>　　常指针和常引用<br/><br/>　　1. 常指针<br/><br/>　　使用const修饰指针时，由于const的位置不同，而含意不同。下面举两个例子，说明它们的区别。<br/><br/>　　下面定义的一个指向字符串的常量指针：<br/><br/>　　 char * const prt1 = stringprt1;<br/><br/>　　其中，ptr1是一个常量指针。因此，下面赋值是非法的。<br/><br/>　　ptr1 = stringprt2;<br/><br/>　　而下面的赋值是合法的：<br/><br/>　　 *ptr1 = &#8220;m&#8221;;<br/><br/>　　因为指针ptr1所指向的变量是可以更新的，不可更新的是常量指针ptr1所指的方向(别的字符串)。<br/><br/>　　下面定义了一个指向字符串常量的指针：<br/><br/>　　 const * ptr2 = stringprt1;<br/><br/>　　其中，ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的，而ptr2是可以更新的。因此，<br/><br/>　　*ptr2 = &#8220;x&#8221;;<br/><br/>　　是非法的，而：<br/><br/>　　ptr2 = stringptr2;<br/><br/>　　是合法的。<br/><br/>　　所以，在使用 const修饰指针时，应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时，const修饰符的位置不同，前者 const放在*和指针名之间，后者const放在类型说明符前。<br/><br/>　　2. 常引用<br/><br/>　　使用const修饰符也可以说明引用，被说明的引用为常引用，该引用所引用的对象不能被更新。其定义格式如下：<br/><br/>　　const <类型说明符> &#038; <引用名><br/><br/>　　例如：<br/><br/>　　const double & v;<br/><br/>　　在实际应用中，常指针和常引用往往用来作函数的形参，这样的参数称为常参数。<br/><br/>　　在C++面向对象的程序设计中，指针和引用使用得较多，其中使用const修饰的常指针和常引用用得更多。使用常参数则表明该函数不会更新某个参数所指向或所引用的对象，这样，在参数传递过程中就不需要执行拷贝初始化构造函数，这将会改善程序的运行效率。<br/><br/>　　下面举一例子说明常指针作函数参数的作法。<br/>
<pre lang="c" linenum="off" ><br/>#include "iostream.h"<br/>const int N = 6;<br/>void print(const int *p, int n);<br/><br/>int main()<br/>{<br/> &nbsp; &nbsp;int array[N];<br/> &nbsp; &nbsp;for (int i=0; i <= 5; cout<<"please input the date" ,cin>>array<i>,i++);<br/> &nbsp; &nbsp;print(array, N);<br/> &nbsp; &nbsp;return 0;<br/>}<br/><br/>void print(const int *p, int n)<br/>{<br/> &nbsp; &nbsp;cout<<"{"<<*p;<br/> &nbsp; &nbsp;for (int i=1; i <= n-1; cout<<","<<*(p+i),i++);<br/> &nbsp; &nbsp;cout<<"}";<br/>}<br/></pre>
<p><br/>常成员函数<br/><br/>　　使用const关键字进行说明的成员函数，称为常成员函数。只有常成员函数才有资格操作常量或常对象，没有使用const关键字说明的成员函数不能用来操作常对象。常成员函数说明格式如下：<br/><br/>　　< 类型说明符> <函数名> (<参数表>) const；<br/><br/>其中，const是加在函数说明后面的类型修饰符，它是函数类型的一个组成部分，因此，在函数实现部分也要带const关键字。下面举一例子说明常成员函数的特征。<br/>
<pre lang="c" linenum="off" ><br/& gt;#include "iostream.h"<br/>class R<br/>{<br/>public:<br/>R(int r1, int r2) { R1=r1; R2=r2; }<br/>void print();<br/>void print() const;<br/>private:<br/>int R1, R2;<br/>};<br/><br/>void R::print()<br/>{<br/>cout<<<","<<br/>}<br/><br/>void R::print() const<br/>{<br/> &nbsp; &nbsp;cout<<<";"<<br/>}<br/><br/>void main()<br/>{<br/> &nbsp; &nbsp;R a(5, 4);<br/> &nbsp; &nbsp;a.print();<br/> &nbsp; &nbsp;const R b(20, 52);<br/> &nbsp; &nbsp;b.print() ;<br/>}<br/></pre>
<p><br/>该程序的类声明了两个成员函数，其类型是不同的(其实就是重载成员函数)。有带const修饰符的成员函数处理const常量，这也体现出函数重载的特点。<br/><br/>　　常数据成员<br/><br/>　　类型修饰符const不仅可以说明成员函数，也可以说明数据成员。<br/><br/>　　由于const类型对象必须被初始化，并且不能更新，因此，在类中说明了const数据成员时，只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。<br/><br/>　　下面通过一个例子讲述使用成员初始化列表来生成构造函数。<br/>
<pre lang="c" linenum="off" ><br/>#include "iostream.h"<br/>class A<br/>{<br/>public:<br/>A(int i);<br/>void print();<br/>const int &#038;r;//引用<br/>private:<br/>const int a;<br/>static const int b;<br/>};<br/><br/>const int A::b=10;<br/>A::A(int i):a(i), r(a)//利用括号里得数给括号外得数赋值<br/>{<br/>}<br/><br/>void A::print()<br/>{<br/> &nbsp; &nbsp;cout<<<":"<<<":"<<br/>}<br/><br/>void main()<br/>{<br/> &nbsp; &nbsp;A a1(100), a2(0);<br/> &nbsp; &nbsp;a1.print();<br/> &nbsp; &nbsp;a2.print();<br/>}<br/></pre>
<p><br/>该程序的运行结果为：<br/><br/>　　100:10:100<br/>　　　 0:10:0<br/><br/>　　在该程序中，说明了如下三个常类型数据成员：<br/><br />　　const int & r;<br/><br/>　　const int a;<br/><br/>　　static const int b;<br/><br/>　　其中，r是常int型引用，a是常int型变量，b是静态常int型变量。<br/><br/>　　程序中对静态数据成员b进行初始化。<br/><br/>　　值得注意的是构造函数的格式如下所示：<br/><br/>　　A(int i):a(i),r(a)<br/>　　{<br/>　　}<br/><br/>　　其中，冒号后边是一个数据成员初始化列表，它包含两个初始化项，用逗号进行了分隔，因为数据成员a和r都是常类型的，需要采用初始化格式。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xixis.net/archives/c-regular-type-const.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[转]对目前主流开发技术的分析和总结</title>
		<link>http://www.xixis.net/archives/ainstream-development-technology.html</link>
		<comments>http://www.xixis.net/archives/ainstream-development-technology.html#comments</comments>
		<pubDate>Thu, 29 Nov 2007 07:37:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[开发]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[c/c++]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[VB]]></category>

		<guid isPermaLink="false">http://127.0.0.1/wp7/?p=63</guid>
		<description><![CDATA[一、引言我为什么要写这篇文章
　　首先，我要限定我文章的范围，我讨论的问题局限于桌面应用开发领域和企业应用开发领域，所以我的结论并不适用于整个软件开发界，比如我说C语言已经退出历史舞台，这对于写嵌入式系统的人和编写操作系统内核的人来说显然是错了。我写这篇文章的目的主要是：
　　　*简单的介绍并评价当前主流技术
　　　*比较当前的主流技术
　　　*预计技术的演变
　　如果你想做程序员或者已经是个程序员，你可能会面对这些困惑：
　　　*学什么语言呢？Delphi、C++、VB、Java、 C#、PHP、Python?
　　　*选择什么开发工具呢？Delphi、VC、C++Builder、 JBuilder?
　　当你已经入了门，有了一定的基础之后（可能已经通晓了几种语言），你会面临进一步的困惑：
　　　*MFC和VCL之间是什么关系？
　　　 *J2EE到底是什么？.Net到底是什么？两者有什么本质的区别，我应该学习哪一个呢？
　　　*COM那么复杂，为什么很多地方都用到它？我必须学习它吗？
　　如果是作为一个软件公司，如果不是那么大，如果你的公司还没有一个真正的技术上的灵魂人物，那么你也会面临同样的困惑。技术问题纷繁复杂，让你不知所从，而且真正的精通每一项技术都需要巨大的时间和人力的投入，你怎么办？选择哪种技术作为公司的主流技术呢？选择的方向是否正确是个关乎你的公司的生死存亡的问题。你面临着这些困惑吗？如果是，那么请让我试着为你拨云见日。

我的故事
　　在我上大学之前，我从没见过计算机。大学的时候，正是Dos和FoxBASE的年代，也正是计算机软件开发世界几件伟大的事情发上的时候：(Windows 3.1、Borland C++3.1、Visual Basic1.0的推出也是伟大的事情，但那时候我还不知道计算机为何物)Widnows 95推出，并开始应用；Visual Basic5.0推出，开发工具中第一次出现了成熟的、被广泛应用的Auto Code Completion技术；Java推出；ASP技术开始盛行,Windows DNA技术被理解和接受；标准C++诞生;Visual C++6.0推出；J2EE规范推出。
　　成为一个程序员对我而言并不顺利，因为我不是科班出身。我入门的程序语言是FoxBASE，这让我一直对FoxBASE有种特殊的感情，我也正是通过VisualFoxPro3.0转写Windows程序的，如果没有它，我也许就不会成为一个程序员了。后来，在大学期间接触到了InterDEV，那是个写ASP程序的开发工具，还有Java，也是那时候接触的，当时有点盲目崇拜的意思（我想我喜欢Java的一个原因可能是刚开始学C的时候很受挫折）。毕业之后，我就是凭借着自己写的一个ASP网站找到了自己的第一份工作——说来惭愧，我从来也没有成为一个C程序员。
　　我真正的熟悉Java是在我翻译了一本Java数据结构的书和写了一套完整的GIS系统之后（说起此事，我要感谢一下我的公司，但因为这些故事与本文的主题无关，所以这里就不多说了）。再后来，我自己学习了标准C++和COM技术。有点像履历表了是吗？提到这些，我只是希望作为读者的你能够了解一下我的知识体系，从而能够知道我大概要讲些什么；同时也希望你能够原谅我可能犯的错误——我在这里说的话，并不一定就是最后的结论，虽然“共同探讨”这个词几乎是粗制滥造的书的作者专用语了，但我在这里引用它是真诚的，我愿意看到你的反馈。要涉及的话题在开始文章的正题之前，我先大概地介绍这篇文章将会涉及到哪些知识。如果你是初学者，希望你不要被吓倒，这虽然是一篇技术文章，但我不会过多的讨论技术细节，如果你不懂我说的这些东西，也没关系，我本来就希望通过我的文章帮助你做出一个选择，不再走很多人已经走过的弯路，你这要记住结论就可以了，随着你知识的增长，以后你会渐渐明白；如果你已经通晓了这些技术或其中的大部分，那么我相信读了这篇文章你会有一些另外的收获。
　　主流的程序设计语言：C++、Delphi(ObjectPascal)、Java、 C#
　　桌面应用程序框架：MFC、VCL、QT、 JavaAWTSWING、.Net
　　企业应用程序框架：WindowsDNA（ASP、COM、 COM+）、J2EE、.NetFramework
　　开发工具：VisualBasic、Delphi、 VisualC++、C++Builder、VisualC#
　　二、正文
　　现在让我们开始我的正文吧。首先，我来完成这篇文章的第一个目标：介绍并评价当前主流技术。我指的今天的主流技术是：
　　　*程序设计语言：C++Delphi（本来应该是ObjectPascal，但为了简单，我就语言和工具混为一谈吧）JavaC#(虽然他刚刚推出，但因为微软为之倾注了大量心血，一定会成为一种重要的开发语言)
　　　*桌面应用程序框架:MFCVCL
　　　*企业应用程序框架:WindowsDNAJ2EE.Net
　　　*COM技术：我单独提出这项技术，是因为它无法简单的被视为语言、桌面应用程序框架或企业应用程序框架，它与这些都有关系。
　　2.1 程序设计语言
　　2.1.1 C++语言的演进
　　最初要从二进制代码和汇编说起，但那太遥远了。我们就从面向过程的语言说起吧（包括 BasicCFortranPascal）。这种面向过程的高级语言终于把计算机带入了寻常的应用领域。其中的C语言因为它的简单和灵活造就了Unix和 Windows这样的伟大的软件。
　　面向对象的语言是计算机语言的一个合乎逻辑的进化，因为在没有过多的影响效率、简单性的前提下提供了一种更好的组织数据的方法，可使程序更容易理解，更容易管理——这一点可能会引出不同意见，但事实胜于雄辩，C++终于让 C语言的领地越来越小，当今还活着的计算机语言或多或少的都具备面向对象的特征，所以这一点并不会引起太多困惑。C++的成功很大程度要归因于C，C++ 成为它今天的样子是合乎逻辑的产物。因为在面向过程的时代，C几乎已经统一天下了。今天著名的语言象JavaC#都从C借鉴了很多东西，C#本来的意思就是C++++。其实C++曾经很有理由统一面向对象程序设计语言的天下来着，但可惜的是，C++太复杂了。即使是一个熟练的程序员，要你很清楚的解释一些问题你也会很头痛。举几个还不是那么复杂的例子来说：
　　对=的重载成员转换函数拷贝构造函数转化构造函数之间有什么区别和联系呢？
　　定义一个类成员函数 private:virtualvoidMemFun()=0;是什么意义呢？
　　int(* (*x(int))[4])(double);是什么意思？
　　还有其他的特征，比如说可以用来制造一种新语言的typedef和宏（虽然宏不是C++的一部分，但它与C++的关系实在太密切了），让你一不小心就摔跤的内存问题（只要new和delete就可以了吗？有没有考虑一个对象存放在容器中的情况？）……诸如此类，C++是如此的复杂以至于要学会它就需要很长的时间，而且你会发现即使你用C++已经好几年了，你还会发现经常有新东西可学。你想解决一个应用领域的问题——比如说从数据库里面查询数据、更改数据那样的问题，可是你却需要首先为C++头痛一阵子才可以，是的，你精通C++，你可以很容易的回答我的问题，可是你有没有想过你付出了多大的代价呢？我不是想过分的谴责C++，我本人喜欢C++，我甚至建议一个认真的开发普通的应用系统的程序员也去学习一下C++，C++中的一些特性，比如说指针运算模板STL几乎让人爱不释手，宏可以用几个字符代替很多代码，对系统级的程序员来说，C++的地位是不可替代的，Java的虚拟机就是C++写的。C++还将继续存在而且有旺盛的生命力。
2.1.2 Java和C#
　　Java和C#相对于C++的不同最大的有两点：第一点是他们运行在一个虚拟环境之中，第二点是语法简单。对于开发人员而言，在语法和语言机制的角度可以把Java和C#视为同一种语言。C#更多的是个政治的产物而不是技术产物。如果不是 Sun为难微软的话，我想微软不会费尽心力推出一个和Java差不多的C++++，记得Visual J++吗，记得WFC吗？看看那些东西就会知道微软为Java曾经倾注了多少心血。而且从更广泛的角度来说，两者也是非常相似的——C#和Java面对的是同样的问题，面向应用领域的问题：事务处理、远程访问、Webservice、Web页面发布、图形界面。那么在这一段中，我暂且用Java这个名字指代Java和C#两种语言——尽管两者在细节上确实有区别。Java是适合解决应用领域的问题的语言。最大的原因Java对于使用者来说非常简单。想想你学会并且能够使用Java需要多长时间，学会并且能够使用C++要多长时间。由于Java很大程度上屏蔽了内存管理问题，而且没有那么多为了微小的性能提升定义的特殊的内容（比如说，在Java里面没有virtual这个关键字,Java也不允许你直接在栈上创建对象，Java明确的区分bool和整型变量），他让你尽量一致的方式操作所有的东西，除了基本数据类型，所有的东西都是对象，你必须通过引用来操作他们；除了这些之外，Java还提供了丰富的类库帮助你解决应用问题——因为它是面向应用的语言，它为你提供了多线程标准、JDBC标准、GUI标准，而这些标准在C++中是不存在的，因为C++并不是直接面向解决应用问题的用户，有人试图在C++中加入这些内容，但并不成功，因为C++本身太复杂了，用这种复杂的语言来实现这种复杂的应用程序框架本身就是一件艰难的事情，稍后我们会提到这种尝试——COM技术。渐渐的，人们不会再用C++开发应用领域的软件，象MFCQTCOM这一类的东西最终也将退出历史舞台。
　　2.1.3 Delphi
　　Delphi是从用C++开发应用系统转向用Java开发应用系统的一个中间产物。它比 C++简单，简单的几乎象Java一样，因为它的简单，定义和使用丰富的类库成为可能，而且Delphi也这么做了，结果就是VCL和其他的组件库。而另一方面，它又比运行于虚拟环境的Java效率要高一些，这样在简单性和效率的平衡之中，Delphi找到了自己的生存空间。而且预计在未来的一段时间之内，这个生存空间将仍然是存在的。可以明显的看出，微软放弃了这个领域，他专注于两方面：系统语言C++和未来的Java(其实是.Net)。也许这对于 Borland来说，是一件很幸运的事情。如果我能够给Borland提一些建议的话，那就是不要把Delphi弄得越来越复杂，如果那样，就是把自己的用户赶到了C++或Java的领地。在虚拟机没有最终占领所有的应用程序开发领域之前，Delphi和Delphi的用户仍然会生存得很好。
　　2.2桌面应用程序框架
　　目前真正成功的桌面应用程序框架只有两个，一个是MFC，一个是VCL，还有一些其他的，但事实上并未进入应用领域。遗憾的是我对两个桌面应用程序框架都不精通。但这不妨碍我对他做出正确的评价。
　　2.2.1MFC
　　MFC（还有曾经的OWL）是SDK编程的正常演化的结果，就象是C++是C的演化结果一样。MFC本身是一件了不起但不那么成功的作品，而且它过时了。这就是我的结论。MFC凝聚了很多天才的智慧——当然，OWL和VCL也一样，侯捷的《深入浅出MFC》把这些智慧摆在了我们的面前。但是这件东西用起来估计不会有人觉得很舒服，如果你一直在用Java、VB或者Delphi，再回过头来用MFC，不舒服的感觉会更加强烈。我不能够解释MFC为什么没有能够最终发展成和VCL一样简单好用的桌面程序框架，也许是微软没精力或者没动力，总之MFC就是那个样子了，而且也不会再有发展，它已经被抛弃了。我有时候想，也许基于C++这种复杂的语言开发MFC这样的东西本身就是错误的——可以开发这样的一个框架，但不应当要求使用它的人熟悉了整个框架之后才能够使用这个系统，但很显然，如果你不了解MFC的内部机制，是不太可能把它用好的，我不能解释清楚为什么会出现这种现象。
　　2.2.2VCL
　　相比之下VCL要成功的得多。我相信很多使用VCL的人可能没有像MFC的用户研究 MFC那样费劲的研究过VCL的内部机制。但这不妨碍他们开发出好用好看的应用程序，这就足够了，还有什么好说的呢？VCL给你提供了一种简单一致的机制，让你可以写出复杂的应用程序。在李维的Borland故事那篇文章中曾经说过，在Borland C++ 3.1推出之后Borland就有人提出开发类似C++ Builder一类的软件，后来竟未成行。是啊，如果C++ Builder是在那个时候出现的，今天的软件开发领域将会是怎么样的世界呢？真的不能想象。也许再过一段时间，这些都将不再重要。因为新生的语言如 Java和C#都提供了类似于VCL的桌面应用程序框架。那个时候，加上Java和C#本身的简单性，如果他们的速度有足够块，连Delphi这种语言也要消失了，还有什么好争论的呢？只是对于今天的桌面程序开发人员来说，VCL确实是最好的选择。
&#60;br /&#62;
2.3 企业应用程序框架
　　2.3.1 Windows DNA
　　Windows DNA的起源无从探究了。随着.Net的推出，事实上Windows DNA将成为历史的陈迹。Windows DNA虽然是几乎所有的企业应用程序开发人员都知道的一个名词，但我相信Windows DNA事实上应用的最广泛的是ASP而不是COM+。真正的COM开发有多少人真正的掌握了呢，更不要提COM+(我有必要解释一下：COM+是COM的执行环境，它提供了一系列如事务处理、安全等基础服务，让应用程序开发人员尽量少在基础架构设计上花精力)——当然我这里指的COM开发不是指VB下的 COM开发，所以要这么说，是因为我觉得如果不能理解用C++进行COM开发，也就不能真正的理解COM技术。如果以一种技术没有被广泛理解和应用作为失败的标志，那么Windows DNA实际上是失败了，但这不是它本身的错，而是基于C++的COM技术的失败造成的。多层应用、系统开发角色分离的概念依然没有过时。
　　2.3.2 J2EE
　　J2EE是第一套成功的企业应用程序开发框架。因为它把事务处理、远程访问、安全这些概念带入了寻常百姓家。这种成功我认为要归因于Java的简单性。Java的简单，对于J2EE容器供应商来说一样重要。开发一个基于Java的应用服务器要比基于C++的更容易。而且由于Java的简单性，应用系统开发者出错的机会也会少一些，不会像C++的开发者那样受到那么多挫折。开发基于Java的企业应用系统的周期会更短，这恐怕是不容争辩的事实。不论如何，是J2EE让事务处理、远程访问、安全这些原来几乎都是用在金融系统中的概念也被一般的企业用户使用并从中获得利益。
　　2.3.3 .NET
　　.Net有什么好说的呢？其实，它不过是微软的J2EE。事务处理、安全、远程访问，这些概念在.Net中都找得到。更有力的说明是，微软也利用了.Net实现了一个PetStore。所以，.Net与J2EE几乎是可以完全对等的。但微软确实是一家值得尊敬的公司——我指从技术上，象Web form这种东西，我相信很多Web应用开发者都梦想过甚至自己实现过，但Sun却一直无动于衷，而且似乎Borland也没有为此作过太多努力，好像有过类似的东西，但肯定是不怎么成功——Borland已经很让人敬佩了，我们也许无法要求太多。
&#60;br /&#62;
2.4 COM技术
　　COM应当是个更广泛的词汇，其实我觉得Axtive X、OLE、Auto mation、COM+都应当提及，因为如果你不理解COM，上面的东西你是无法理解的。而且，我只是想说明COM是一种即将消亡的技术，仅仅说说COM 的复杂性和他的问题就够了，所以不会提及那些东西。为什么会出现COM技术？COM的根本目标是实现代码的对象化的二进制重用，进而实现软件的组件化、软件开发工作的分工。这要求他做到两点：第一，能够跨越不同的语言，第二，要跨越同一种语言的不同编译器。COM技术为这个目标付出了沉重的代价，尤其是为了跨越不同的编译器，以至于无论对于使用者而言还是开发者而言，他都是一个痛苦的技术。但幸运的事，这一切终归要结束了。
　　让我们从这个目的出发看看COM为什么会成为它现在的样子。其实COM不是什么新玩意，最初的 DLL就是重用二进制代码的技术。DLL在C的年代可能还不错，但到了C++的年代就不行了。原因在于如果你在.h文件中改变了类定义（增加或者减少了成员变量），代码库用户的代码必须重新编译才可以，否则用户的代码会按你的旧类的结构为你的新类分配内存，这将产生什么后果可想而知。这就是为什么通过接口继承和通过接口操作对象成为COM的强制规范的原因，能够通过对象的方式组织代码是COM的重要努力。那么著名的IUnknown接口又是怎么回事呢？这是为了让使用不同编译器的C++开发人员能够共享劳动成果。
　　首先看QueryInterface，因为 COM是基于接口的，那么一个类可能实现了几个接口，而对于用户来说，你又只能通过操作接口来操作类，这样你必须把类造型成某个特定的接口，使用 Dynamic_cast吗？不行，因为这是编译器相关的，那么，就只好把它放在类的实现代码中了，这就是QueryInterface的由来。至于 AddRef和Release，他们产生的第一个原因是delete这个操作要求一个类具有虚析构函数（否则的话，他的父类的析构函数将不会被调用），但不幸的是不同的编译器中析构函数在vtbl中的位置并不相同，这就是说你不能让用户直接调用delete，那么你的COM对象必须提供自己删除自己的方法；另外的原因在于一个COM对象可能作为几个接口在被用户同时使用，如果用户粗暴的删掉了某个接口，那么其他的接口也就不能用了，这样，只好要求用户在想用一个接口的时候通过AddRef通知COM对象“我要使用你了，你多了一个用户”，而在不用之后要调用Release告诉COM对象“我不用你了，你少了一个用户”，如果COM对象发现自己没有用户了，它就把自己删掉。
　　再看看诡异的HRESULT，这是跨语言和跨编译器的代价。其实，异常处理是物竞天择的结果——连一直用效率作标榜的C++都肯牺牲效率来实现这个try-catch，可见它的意义，但 COM为了照顾那些低级的语言居然抛弃了这个特征——产生的结果就是HRESULT。我们可以看看他是多么愚蠢的东西。首先，我们要通过一个整数来传递错误信息，通过IErrorInfo来查找真正的错误描述，本来在现代语言中一个try-catch可以解决的问题，现在我们却需要让用户和开发者都走很多路才能解决，你怎么评价这个结果？其次，由于这个返回计算结果的位置被占用了，我们不得不用怪异的out参数来返回结果。想想一个简单的int add(intop1,intop2)在COM中竟然要变成HRESULT add(intop1,intop2,int* result)，我不知道你对此作何感想。而且由于COM的方法无法返回一个对象而只能返回一个指针，为了完成一个简单的std::string GetName()这一类的操作，你要费多少周折——你需要先分配一块内存空间，然后在COM实现中把一个字符串拷贝到这个空间，用完了你要删掉这个空间，不知道你是否觉得这种工作很幸福，反正我觉得很痛苦。还有COM为了照顾那些解释性的语言，又加入了Automation技术，你有没有为此觉得痛苦？本来一个简单的方法调用，现在却需要传给你一个标志变量，然后让你根据这个标志变量去执行相应的操作。（这一点我现在仍然不明白，为什么解释性的语言需要通过这个方式来执行一个方法）。“我受够了，我觉得头痛”，你会说，是啊，我想所有的人都受够了，所有这些因素实际上是把COM技术变成了一头让人无法驾驭的怪兽。
　　人对复杂事物的掌控能力终究是有限的，C++本身已经够复杂了，COM的复杂性已经超出了我们大部分人的控制能力，你需要忍受种种痛苦得到的东西与你付出的代价相比是不是太不值得了？我们学习是为了解决问题，而现在我们却需要为了学习这件事情本身耗费太多的精力。这些痛苦的东西太多了，我在这里说到的，其实只是一小部分而已。计算机技术是为人类服务的，而不是少数人的游戏（我想COM技术可能是他的设计者和一部分技术作者的游戏），难道我们愿意成为计算机的奴隶吗？通过一种过于复杂的技术抛弃所有的人其实等于被所有的人抛弃，这么多年中选择 J2EE的人我相信不乏高手，你是不是因为COM的过于复杂才选择J2EE的？因为它可以用简单的途径实现差不多的目标——软件的“二进制”重用、组件化、专业分工（容器开发商和应用开发商的分工）。事实上，你是被微软所抛弃的，同时，你也抛弃了微软。
　　现在让我们回来吧，我把你带进了COM的迷宫，现在让我把你领回来。再让我们看看COM到底想实现什么目标，其实很简单，不过是代码的二进制重用，也就是说你不必给别人源代码，而且你的组件可以象计算机硬件那样“即插即用”。我们回过头来看看Java，其实，这种二进制重用的困难是C++所带来的（这不是 C++本身的错，而是静态编译的错），当Java出现的时候，很多问题已经不存在了。你不需要一个头文件，因为Java的字节码是自解释的，它说明了自己是什么样子的，可以做什么事情。不像C++那样需要一个头文件来解释这些事情；也不需要事先了解对象的内存结构，因为内存是在运行的时候才分配的。如果我们现在再回过头来解决COM要解决的问题，你会怎么做呢？首先你会不再选择C++这种语言来实现代码的“二进制”重用，其次，你会把所有的语言编译成同样的“二进制”代码（实际上，应当说是字节码），这显然是更聪明的做法，从前COM试图在源代码的级别抹平二进制层次的差异，这实际上是让人在做本来应当由机器做的事情，很愚蠢是吗？但他们一直做了那么多年，而且把这个痛苦带给了整个计算机世界——因为他们掌握着事实的标准，为了用户，为了利润，为了能够在 Windows上运行，尽管你知道你在做着一个很不聪明的事情，但你还是做了。
　　COM技术为了照顾VB 这个小兄弟和实现统一二进制世界的野心，实在浪费了太多的精力。首先，落后的东西的消亡是必然的，就象C、Pascal在应用领域的消亡一样，Basic 一点一点的改良运动是不符合历史潮流的做法，先进的东西和落后的东西在一起，要么先进的东西被落后的东西拖住后腿，要么是同化落后的东西，显然我们更愿意看见后者，现在Basic终于被现代的计算机语言同化了。其次，统一二进制世界好像不是那么简单的事情，而且也没什么必要，微软的COM技术奋战了10 年，现在也只有他自己和Borland支持，.Net终于放弃了这个野心。这一切终于要结束了。
　　过去 J2EE高歌猛进地占领着应用开发的领地，COM在这种进攻面前多少显得苍白无力。现在微软终于也有了可以和J2EE一较长短的.NET，对于开发人员来讲，基于字节码的组件的二进制重用现在是天经地义的事情；你不用再为了能够以类方式发布组件做那么多乱七八糟的事情，因为现在所有的东西本来就是类了；实现软件开发的分工也很自然，你是专业人员，就用C#吧，你是应用开发人员，你喜欢用VB.Net，你就用吧，反正你们写的东西最终都被翻译成了一样的语言（其实我觉得这一点意义不大，因为一些不那么好用的语言被淘汰是正常的事情，C风格成为程序设计语言的主流风格，肯定是有它的原因的，语言的统一其实是大势所趋，就象中国人民都要说普通话一样，我觉得Java不支持多语言算不上缺点——本来就是一种很好看很好用的语言了，为什么要把简单问题复杂化呢？）。 COM不会在短期内死去，因为我估计微软还不会马上用C#开发Office和Windows的图形界面部分，但我相信COM技术退出历史舞台的日子已经不远了，作为一般的开发人员，忘了这段不愉快的历史吧——你将不会在你的世界里直接和COM打交道。若干年以后，我想COM也许会成为一场笑话，用来讽刺那种野心过大、钻牛角尖的愚蠢的聪明人。
结论
&#60;br /&#62;　　说了很多，应该是有个结论的时候了。我似乎做了一件冒天下之大不韪的事情，因为我评价了主流技术，还要试图进行比较，好像某个名人说过：“C++ Builder也好，Visual C++也好，能在市场上立足，肯定都是有自己的过人之处的，而且一个人精通数种开发语言、数种开发工具是不可能的事情”，言下之意就是说你不要对这些东西妄加评论，但怎么可以不评论？好像高手都不屑于说哪种语言好、哪种语言坏，我不知道什么时候形成了这种风气。简单地说C++比Java好或者Java比 C++好显然是愚蠢的行为，但如果让你用Java写驱动程序，用C++开发一个MIS系统是不是愚蠢的行为呢？显然更愚蠢。我想，作为一个独立的能思考的人，外界的东西对你而言总是有好有坏，而且你的生命有限，你还要享受你的生活，所以你必须做出选择。所以，起码评价这些东西对我自己而言是正确的——只要我有能力评价，那我就说出我的评价吧。
　　对于计算机语言来说，未来真正重要的语言只有三种C++、 Java和C#。C++将更适合于专业的计算机公司编写图形界面系统（比如KDE）、虚拟机（比如Java虚拟机或者.Net运行环境）、杀毒软件或者其他的盒装软件（比如说Photoshop、Dreamweaver）这一类的东西。而且C++适合程序员做学习之用，能对C++有一定理解的程序员往往也应该能更深刻的理解Java、C#，这有助于编写更好的软件。如果是开发为客户定制的应用系统Java、C#是更好的选择。包括桌面应用和Web应用。
　　至于其他的语言比如VB.Net其实并没有太大的意义。Delphi在未来一段时间将继续存在，而且活得不错。最重要的原因在于，第一它有一套丰富的组件库，第二它效率相对算高的，第三它简单。如果虚拟机的执行效率赶不上Delphi，它就有存在的理由，但从过去的Visual J++来看，微软的虚拟机做得确实可以很好，加上.Net的组件库和C#的简单性并不差，所以从长远来看Delphi可能不那么乐观。
　　其实上面的比较也包含了桌面应用程序框架的比较。在现在来说VCL无疑最好的，MFC已经退出历史舞台。.Net中所带的桌面应用程序框架将最终统一桌面应用领域（但不包括微软和Borland这样的专业公司，因为他们要作出最好用而且效率最高的软件）。至于Java中所带的桌面应用程序框架，实在让人哭笑不得。这个结论的变数是.Net运行环境的执行效率。如果.Net中的虚拟机象Java的一样，那微软就倒霉了，它等于放弃了桌面应用开发工具领域，但根据微软在Visual J++上的成就和他推广.Net的背水一战的驾式，.Net在桌面领域失败的可能性不大（但不是没有，起码基于COM的技术在企业应用领域几乎可以说是全军覆没）。
　　在企业应用程序框架领域，最终只有J2EE和.Net可以决一雌雄。我没有提到CORBA，它也可以算是企业应用程序框架，但他的声势和J2EE或者.NET实在不能同日而语，而且最重要的是只有Borland一家大公司支持它（SUN、 IBM、BEA、Borland支持J2EE，微软就不用说了），所以就不详细说他了。那么最终谁会赢呢？我想微软赢的可能性大一些。这样说可能让很多人不快，而且IBM的厉害也是有目共睹的。但这并不是纯技术问题，就象Windows NT蚕食Unix的领土那样，那时候微软也是孤军作战。J2EE的问题在于第一：混乱，第二，价高。我相信很多人都对这两点有过不快的经历。你知道写给 Weblogic的应用程序不是很顺利地就可以移植到Websphere上的，反过来也一样。但.Net就不一样了，那是微软一个人的作品，根本不存在移植的问题。
　　如果J2EE阵营不想败在这一点上，有三个办法，第一种就是通过制定统一的标准彻底消灭移植问题，第二种是开发一种好用的部署工具（不能象JBuilder那么大、那么慢：），屏蔽不同的应用程序容器之间的区别，第三种，也是最不可能的，就是 J2EE阵营有人能够一统天下。显然，这三种解决办法都不太现实。第二点价高，这是SUN、IBM、BEA、ORACLE传统，也是它们一直让微软的进攻屡屡得手的软肋。我一直不太能明白他们的西就为什么那么贵。这样想一想：微软的.Net SDK白送给你，BEA的Web logic一个CPU的License两万，如果你两种技术都会，如果你给客户的系统报价一样，你选哪种开发技术？这一点实在让人觉得无可奈何。J2EE 有的东西，.Net也有（除了不能跨平台），技术上的细微差别在巨大的价格差异面前还有什么意义呢？当然，SUM、IBM这些大公司也不是等闲之辈。就象 Windows NT没有消灭Unix一样，J2EE应当会像Windows NT和Unix的共存一样和.Net共存，只是我想.Net恐怕会占上风。
　　闲话
　　说完了该说的技术问题，说说闲话吧。有的话放在心里觉得不说出来不舒服，且让我一吐为快:)
　　给入门程序员的建议
　　不知道我在学计算机的时候是不是走了弯路。但我想如果让我重新开始学写程序的话，我会采用一些不同的办法。如果你也正在想成为一个程序员，这些也许会对你有帮助。我觉得可能大概要分几个阶段，第一个阶段应该是找一门简单的语言入门，比如Java或者C#都应该比较合适，选一本简单的带例子的书（最好不要太厚），按部就班的把书学完。这时候可能还有些懵懵懂懂，但没关系，可以开始做个小小的软件了，重要的事你要自己用那种语言的方式想思考，如果有项目做，当然更好。之后，你会觉得有点感觉了。如果你象我一样不是科班出身的，接下来应当补习一下计算机专业的课程，我觉得最重要的是数据结构——那些东西你可能永远都不会自己做，C++ 中有漂亮的STL，Java中也为你实现了大部分东西，但我觉得真的有必要学习那些内容，这会加强你用计算机语言思考问题的能力。在进一步，如果你的入门语言不是C++，那你可以补习一下C++，尽管你可能永远都不会用C++开发程序。C++在现在的计算机世界就象是普通话一样，而且它能让你很容易的理解其他语言中难以理解的问题。学完了C++，那你应当就已经不是一个初级程序员了，欢迎你进入计算机软件开发的世界。
&#60;br ...]]></description>
			<content:encoded><![CDATA[<p>一、引言我为什么要写这篇文章</p>
<p>　　首先，我要限定我文章的范围，我讨论的问题局限于桌面应用开发领域和企业应用开发领域，所以我的结论并不适用于整个软件开发界，比如我说C语言已经退出历史舞台，这对于写嵌入式系统的人和编写操作系统内核的人来说显然是错了。我写这篇文章的目的主要是：</p>
<p>　　　*简单的介绍并评价当前主流技术</p>
<p>　　　*比较当前的主流技术</p>
<p>　　　*预计技术的演变</p>
<p>　　如果你想做程序员或者已经是个程序员，你可能会面对这些困惑：</p>
<p>　　　*学什么语言呢？<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/delphi" title="显示Delphi的所有日志" target="_blank">Delphi</a></span>、C++、<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/vb" title="显示VB的所有日志" target="_blank">VB</a></span>、Java、 C#、PHP、<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/python" title="显示Python的所有日志" target="_blank">Python</a></span>?</p>
<p>　　　*选择什么开发工具呢？<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/delphi" title="显示Delphi的所有日志" target="_blank">Delphi</a></span>、VC、C++Builder、 JBuilder?</p>
<p>　　当你已经入了门，有了一定的基础之后（可能已经通晓了几种语言），你会面临进一步的困惑：</p>
<p>　　　*MFC和VCL之间是什么关系？</p>
<p>　　　 *J2EE到底是什么？.Net到底是什么？两者有什么本质的区别，我应该学习哪一个呢？</p>
<p>　　　*COM那么复杂，为什么很多地方都用到它？我必须学习它吗？</p>
<p>　　如果是作为一个软件公司，如果不是那么大，如果你的公司还没有一个真正的技术上的灵魂人物，那么你也会面临同样的困惑。技术问题纷繁复杂，让你不知所从，而且真正的精通每一项技术都需要巨大的时间和人力的投入，你怎么办？选择哪种技术作为公司的主流技术呢？选择的方向是否正确是个关乎你的公司的生死存亡的问题。你面临着这些困惑吗？如果是，那么请让我试着为你拨云见日。<br />
<span id="more-63"></span><br />
我的故事</p>
<p>　　在我上大学之前，我从没见过计算机。大学的时候，正是Dos和FoxBASE的年代，也正是计算机软件开发世界几件伟大的事情发上的时候：(Windows 3.1、Borland C++3.1、Visual Basic1.0的推出也是伟大的事情，但那时候我还不知道计算机为何物)Widnows 95推出，并开始应用；Visual Basic5.0推出，开发工具中第一次出现了成熟的、被广泛应用的Auto Code Completion技术；Java推出；ASP技术开始盛行,Windows DNA技术被理解和接受；标准C++诞生;Visual C++6.0推出；J2EE规范推出。</p>
<p>　　成为一个程序员对我而言并不顺利，因为我不是科班出身。我入门的程序语言是FoxBASE，这让我一直对FoxBASE有种特殊的感情，我也正是通过VisualFoxPro3.0转写Windows程序的，如果没有它，我也许就不会成为一个程序员了。后来，在大学期间接触到了InterDEV，那是个写ASP程序的开发工具，还有Java，也是那时候接触的，当时有点盲目崇拜的意思（我想我喜欢Java的一个原因可能是刚开始学C的时候很受挫折）。毕业之后，我就是凭借着自己写的一个ASP网站找到了自己的第一份工作——说来惭愧，我从来也没有成为一个C程序员。</p>
<p>　　我真正的熟悉Java是在我翻译了一本Java数据结构的书和写了一套完整的GIS系统之后（说起此事，我要感谢一下我的公司，但因为这些故事与本文的主题无关，所以这里就不多说了）。再后来，我自己学习了标准C++和COM技术。有点像履历表了是吗？提到这些，我只是希望作为读者的你能够了解一下我的知识体系，从而能够知道我大概要讲些什么；同时也希望你能够原谅我可能犯的错误——我在这里说的话，并不一定就是最后的结论，虽然“共同探讨”这个词几乎是粗制滥造的书的作者专用语了，但我在这里引用它是真诚的，我愿意看到你的反馈。要涉及的话题在开始文章的正题之前，我先大概地介绍这篇文章将会涉及到哪些知识。如果你是初学者，希望你不要被吓倒，这虽然是一篇技术文章，但我不会过多的讨论技术细节，如果你不懂我说的这些东西，也没关系，我本来就希望通过我的文章帮助你做出一个选择，不再走很多人已经走过的弯路，你这要记住结论就可以了，随着你知识的增长，以后你会渐渐明白；如果你已经通晓了这些技术或其中的大部分，那么我相信读了这篇文章你会有一些另外的收获。</p>
<p>　　主流的程序设计语言：C++、<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/delphi" title="显示Delphi的所有日志" target="_blank">Delphi</a></span>(ObjectPascal)、Java、 C#</p>
<p>　　桌面应用程序框架：MFC、VCL、QT、 JavaAWTSWING、.Net</p>
<p>　　企业应用程序框架：WindowsDNA（ASP、COM、 COM+）、J2EE、.NetFramework</p>
<p>　　开发工具：VisualBasic、Delphi、 VisualC++、C++Builder、VisualC#</p>
<p>　　二、正文</p>
<p>　　现在让我们开始我的正文吧。首先，我来完成这篇文章的第一个目标：介绍并评价当前主流技术。我指的今天的主流技术是：</p>
<p>　　　*程序设计语言：C++Delphi（本来应该是ObjectPascal，但为了简单，我就语言和工具混为一谈吧）JavaC#(虽然他刚刚推出，但因为微软为之倾注了大量心血，一定会成为一种重要的开发语言)</p>
<p>　　　*桌面应用程序框架:MFCVCL</p>
<p>　　　*企业应用程序框架:WindowsDNAJ2EE.Net</p>
<p>　　　*COM技术：我单独提出这项技术，是因为它无法简单的被视为语言、桌面应用程序框架或企业应用程序框架，它与这些都有关系。</p>
<p>　　2.1 程序设计语言</p>
<p>　　2.1.1 C++语言的演进</p>
<p>　　最初要从二进制代码和汇编说起，但那太遥远了。我们就从面向过程的语言说起吧（包括 BasicCFortranPascal）。这种面向过程的高级语言终于把计算机带入了寻常的应用领域。其中的C语言因为它的简单和灵活造就了Unix和 Windows这样的伟大的软件。</p>
<p>　　面向对象的语言是计算机语言的一个合乎逻辑的进化，因为在没有过多的影响效率、简单性的前提下提供了一种更好的组织数据的方法，可使程序更容易理解，更容易管理——这一点可能会引出不同意见，但事实胜于雄辩，C++终于让 C语言的领地越来越小，当今还活着的计算机语言或多或少的都具备面向对象的特征，所以这一点并不会引起太多困惑。C++的成功很大程度要归因于C，C++ 成为它今天的样子是合乎逻辑的产物。因为在面向过程的时代，C几乎已经统一天下了。今天著名的语言象JavaC#都从C借鉴了很多东西，C#本来的意思就是C++++。其实C++曾经很有理由统一面向对象程序设计语言的天下来着，但可惜的是，C++太复杂了。即使是一个熟练的程序员，要你很清楚的解释一些问题你也会很头痛。举几个还不是那么复杂的例子来说：</p>
<p>　　对=的重载成员转换函数拷贝构造函数转化构造函数之间有什么区别和联系呢？</p>
<p>　　定义一个类成员函数 private:virtualvoidMemFun()=0;是什么意义呢？</p>
<p>　　int(* (*x(int))[4])(double);是什么意思？</p>
<p>　　还有其他的特征，比如说可以用来制造一种新语言的typedef和宏（虽然宏不是C++的一部分，但它与C++的关系实在太密切了），让你一不小心就摔跤的内存问题（只要new和delete就可以了吗？有没有考虑一个对象存放在容器中的情况？）……诸如此类，C++是如此的复杂以至于要学会它就需要很长的时间，而且你会发现即使你用C++已经好几年了，你还会发现经常有新东西可学。你想解决一个应用领域的问题——比如说从数据库里面查询数据、更改数据那样的问题，可是你却需要首先为C++头痛一阵子才可以，是的，你精通C++，你可以很容易的回答我的问题，可是你有没有想过你付出了多大的代价呢？我不是想过分的谴责C++，我本人喜欢C++，我甚至建议一个认真的开发普通的应用系统的程序员也去学习一下C++，C++中的一些特性，比如说指针运算模板STL几乎让人爱不释手，宏可以用几个字符代替很多代码，对系统级的程序员来说，C++的地位是不可替代的，Java的虚拟机就是C++写的。C++还将继续存在而且有旺盛的生命力。</p>
<p>2.1.2 Java和C#</p>
<p>　　Java和C#相对于C++的不同最大的有两点：第一点是他们运行在一个虚拟环境之中，第二点是语法简单。对于开发人员而言，在语法和语言机制的角度可以把Java和C#视为同一种语言。C#更多的是个政治的产物而不是技术产物。如果不是 Sun为难微软的话，我想微软不会费尽心力推出一个和Java差不多的C++++，记得Visual J++吗，记得WFC吗？看看那些东西就会知道微软为Java曾经倾注了多少心血。而且从更广泛的角度来说，两者也是非常相似的——C#和Java面对的是同样的问题，面向应用领域的问题：事务处理、远程访问、Webservice、Web页面发布、图形界面。那么在这一段中，我暂且用Java这个名字指代Java和C#两种语言——尽管两者在细节上确实有区别。Java是适合解决应用领域的问题的语言。最大的原因Java对于使用者来说非常简单。想想你学会并且能够使用Java需要多长时间，学会并且能够使用C++要多长时间。由于Java很大程度上屏蔽了内存管理问题，而且没有那么多为了微小的性能提升定义的特殊的内容（比如说，在Java里面没有virtual这个关键字,Java也不允许你直接在栈上创建对象，Java明确的区分bool和整型变量），他让你尽量一致的方式操作所有的东西，除了基本数据类型，所有的东西都是对象，你必须通过引用来操作他们；除了这些之外，Java还提供了丰富的类库帮助你解决应用问题——因为它是面向应用的语言，它为你提供了多线程标准、JDBC标准、GUI标准，而这些标准在C++中是不存在的，因为C++并不是直接面向解决应用问题的用户，有人试图在C++中加入这些内容，但并不成功，因为C++本身太复杂了，用这种复杂的语言来实现这种复杂的应用程序框架本身就是一件艰难的事情，稍后我们会提到这种尝试——COM技术。渐渐的，人们不会再用C++开发应用领域的软件，象MFCQTCOM这一类的东西最终也将退出历史舞台。</p>
<p>　　2.1.3 Delphi</p>
<p>　　Delphi是从用C++开发应用系统转向用Java开发应用系统的一个中间产物。它比 C++简单，简单的几乎象Java一样，因为它的简单，定义和使用丰富的类库成为可能，而且Delphi也这么做了，结果就是VCL和其他的组件库。而另一方面，它又比运行于虚拟环境的Java效率要高一些，这样在简单性和效率的平衡之中，Delphi找到了自己的生存空间。而且预计在未来的一段时间之内，这个生存空间将仍然是存在的。可以明显的看出，微软放弃了这个领域，他专注于两方面：系统语言C++和未来的Java(其实是.Net)。也许这对于 Borland来说，是一件很幸运的事情。如果我能够给Borland提一些建议的话，那就是不要把Delphi弄得越来越复杂，如果那样，就是把自己的用户赶到了C++或Java的领地。在虚拟机没有最终占领所有的应用程序开发领域之前，Delphi和Delphi的用户仍然会生存得很好。</p>
<p>　　2.2桌面应用程序框架</p>
<p>　　目前真正成功的桌面应用程序框架只有两个，一个是MFC，一个是VCL，还有一些其他的，但事实上并未进入应用领域。遗憾的是我对两个桌面应用程序框架都不精通。但这不妨碍我对他做出正确的评价。</p>
<p>　　2.2.1MFC</p>
<p>　　MFC（还有曾经的OWL）是SDK编程的正常演化的结果，就象是C++是C的演化结果一样。MFC本身是一件了不起但不那么成功的作品，而且它过时了。这就是我的结论。MFC凝聚了很多天才的智慧——当然，OWL和VCL也一样，侯捷的《深入浅出MFC》把这些智慧摆在了我们的面前。但是这件东西用起来估计不会有人觉得很舒服，如果你一直在用Java、<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/vb" title="显示VB的所有日志" target="_blank">VB</a></span>或者Delphi，再回过头来用MFC，不舒服的感觉会更加强烈。我不能够解释MFC为什么没有能够最终发展成和VCL一样简单好用的桌面程序框架，也许是微软没精力或者没动力，总之MFC就是那个样子了，而且也不会再有发展，它已经被抛弃了。我有时候想，也许基于C++这种复杂的语言开发MFC这样的东西本身就是错误的——可以开发这样的一个框架，但不应当要求使用它的人熟悉了整个框架之后才能够使用这个系统，但很显然，如果你不了解MFC的内部机制，是不太可能把它用好的，我不能解释清楚为什么会出现这种现象。</p>
<p>　　2.2.2VCL</p>
<p>　　相比之下VCL要成功的得多。我相信很多使用VCL的人可能没有像MFC的用户研究 MFC那样费劲的研究过VCL的内部机制。但这不妨碍他们开发出好用好看的应用程序，这就足够了，还有什么好说的呢？VCL给你提供了一种简单一致的机制，让你可以写出复杂的应用程序。在李维的Borland故事那篇文章中曾经说过，在Borland C++ 3.1推出之后Borland就有人提出开发类似C++ Builder一类的软件，后来竟未成行。是啊，如果C++ Builder是在那个时候出现的，今天的软件开发领域将会是怎么样的世界呢？真的不能想象。也许再过一段时间，这些都将不再重要。因为新生的语言如 Java和C#都提供了类似于VCL的桌面应用程序框架。那个时候，加上Java和C#本身的简单性，如果他们的速度有足够块，连Delphi这种语言也要消失了，还有什么好争论的呢？只是对于今天的桌面程序开发人员来说，VCL确实是最好的选择。<br />
&lt;br /&gt;<br />
2.3 企业应用程序框架</p>
<p>　　2.3.1 Windows DNA</p>
<p>　　Windows DNA的起源无从探究了。随着.Net的推出，事实上Windows DNA将成为历史的陈迹。Windows DNA虽然是几乎所有的企业应用程序开发人员都知道的一个名词，但我相信Windows DNA事实上应用的最广泛的是ASP而不是COM+。真正的COM开发有多少人真正的掌握了呢，更不要提COM+(我有必要解释一下：COM+是COM的执行环境，它提供了一系列如事务处理、安全等基础服务，让应用程序开发人员尽量少在基础架构设计上花精力)——当然我这里指的COM开发不是指<span class='wp_keywordlink_affiliate'><a href="http://www.xixis.net/archives/tag/vb" title="显示VB的所有日志" target="_blank">VB</a></span>下的 COM开发，所以要这么说，是因为我觉得如果不能理解用C++进行COM开发，也就不能真正的理解COM技术。如果以一种技术没有被广泛理解和应用作为失败的标志，那么Windows DNA实际上是失败了，但这不是它本身的错，而是基于C++的COM技术的失败造成的。多层应用、系统开发角色分离的概念依然没有过时。</p>
<p>　　2.3.2 J2EE</p>
<p>　　J2EE是第一套成功的企业应用程序开发框架。因为它把事务处理、远程访问、安全这些概念带入了寻常百姓家。这种成功我认为要归因于Java的简单性。Java的简单，对于J2EE容器供应商来说一样重要。开发一个基于Java的应用服务器要比基于C++的更容易。而且由于Java的简单性，应用系统开发者出错的机会也会少一些，不会像C++的开发者那样受到那么多挫折。开发基于Java的企业应用系统的周期会更短，这恐怕是不容争辩的事实。不论如何，是J2EE让事务处理、远程访问、安全这些原来几乎都是用在金融系统中的概念也被一般的企业用户使用并从中获得利益。</p>
<p>　　2.3.3 .NET</p>
<p>　　.Net有什么好说的呢？其实，它不过是微软的J2EE。事务处理、安全、远程访问，这些概念在.Net中都找得到。更有力的说明是，微软也利用了.Net实现了一个PetStore。所以，.Net与J2EE几乎是可以完全对等的。但微软确实是一家值得尊敬的公司——我指从技术上，象Web form这种东西，我相信很多Web应用开发者都梦想过甚至自己实现过，但Sun却一直无动于衷，而且似乎Borland也没有为此作过太多努力，好像有过类似的东西，但肯定是不怎么成功——Borland已经很让人敬佩了，我们也许无法要求太多。<br />
&lt;br /&gt;<br />
2.4 COM技术</p>
<p>　　COM应当是个更广泛的词汇，其实我觉得Axtive X、OLE、Auto mation、COM+都应当提及，因为如果你不理解COM，上面的东西你是无法理解的。而且，我只是想说明COM是一种即将消亡的技术，仅仅说说COM 的复杂性和他的问题就够了，所以不会提及那些东西。为什么会出现COM技术？COM的根本目标是实现代码的对象化的二进制重用，进而实现软件的组件化、软件开发工作的分工。这要求他做到两点：第一，能够跨越不同的语言，第二，要跨越同一种语言的不同编译器。COM技术为这个目标付出了沉重的代价，尤其是为了跨越不同的编译器，以至于无论对于使用者而言还是开发者而言，他都是一个痛苦的技术。但幸运的事，这一切终归要结束了。</p>
<p>　　让我们从这个目的出发看看COM为什么会成为它现在的样子。其实COM不是什么新玩意，最初的 DLL就是重用二进制代码的技术。DLL在C的年代可能还不错，但到了C++的年代就不行了。原因在于如果你在.h文件中改变了类定义（增加或者减少了成员变量），代码库用户的代码必须重新编译才可以，否则用户的代码会按你的旧类的结构为你的新类分配内存，这将产生什么后果可想而知。这就是为什么通过接口继承和通过接口操作对象成为COM的强制规范的原因，能够通过对象的方式组织代码是COM的重要努力。那么著名的IUnknown接口又是怎么回事呢？这是为了让使用不同编译器的C++开发人员能够共享劳动成果。</p>
<p>　　首先看QueryInterface，因为 COM是基于接口的，那么一个类可能实现了几个接口，而对于用户来说，你又只能通过操作接口来操作类，这样你必须把类造型成某个特定的接口，使用 Dynamic_cast吗？不行，因为这是编译器相关的，那么，就只好把它放在类的实现代码中了，这就是QueryInterface的由来。至于 AddRef和Release，他们产生的第一个原因是delete这个操作要求一个类具有虚析构函数（否则的话，他的父类的析构函数将不会被调用），但不幸的是不同的编译器中析构函数在vtbl中的位置并不相同，这就是说你不能让用户直接调用delete，那么你的COM对象必须提供自己删除自己的方法；另外的原因在于一个COM对象可能作为几个接口在被用户同时使用，如果用户粗暴的删掉了某个接口，那么其他的接口也就不能用了，这样，只好要求用户在想用一个接口的时候通过AddRef通知COM对象“我要使用你了，你多了一个用户”，而在不用之后要调用Release告诉COM对象“我不用你了，你少了一个用户”，如果COM对象发现自己没有用户了，它就把自己删掉。</p>
<p>　　再看看诡异的HRESULT，这是跨语言和跨编译器的代价。其实，异常处理是物竞天择的结果——连一直用效率作标榜的C++都肯牺牲效率来实现这个try-catch，可见它的意义，但 COM为了照顾那些低级的语言居然抛弃了这个特征——产生的结果就是HRESULT。我们可以看看他是多么愚蠢的东西。首先，我们要通过一个整数来传递错误信息，通过IErrorInfo来查找真正的错误描述，本来在现代语言中一个try-catch可以解决的问题，现在我们却需要让用户和开发者都走很多路才能解决，你怎么评价这个结果？其次，由于这个返回计算结果的位置被占用了，我们不得不用怪异的out参数来返回结果。想想一个简单的int add(intop1,intop2)在COM中竟然要变成HRESULT add(intop1,intop2,int* result)，我不知道你对此作何感想。而且由于COM的方法无法返回一个对象而只能返回一个指针，为了完成一个简单的std::string GetName()这一类的操作，你要费多少周折——你需要先分配一块内存空间，然后在COM实现中把一个字符串拷贝到这个空间，用完了你要删掉这个空间，不知道你是否觉得这种工作很幸福，反正我觉得很痛苦。还有COM为了照顾那些解释性的语言，又加入了Automation技术，你有没有为此觉得痛苦？本来一个简单的方法调用，现在却需要传给你一个标志变量，然后让你根据这个标志变量去执行相应的操作。（这一点我现在仍然不明白，为什么解释性的语言需要通过这个方式来执行一个方法）。“我受够了，我觉得头痛”，你会说，是啊，我想所有的人都受够了，所有这些因素实际上是把COM技术变成了一头让人无法驾驭的怪兽。</p>
<p>　　人对复杂事物的掌控能力终究是有限的，C++本身已经够复杂了，COM的复杂性已经超出了我们大部分人的控制能力，你需要忍受种种痛苦得到的东西与你付出的代价相比是不是太不值得了？我们学习是为了解决问题，而现在我们却需要为了学习这件事情本身耗费太多的精力。这些痛苦的东西太多了，我在这里说到的，其实只是一小部分而已。计算机技术是为人类服务的，而不是少数人的游戏（我想COM技术可能是他的设计者和一部分技术作者的游戏），难道我们愿意成为计算机的奴隶吗？通过一种过于复杂的技术抛弃所有的人其实等于被所有的人抛弃，这么多年中选择 J2EE的人我相信不乏高手，你是不是因为COM的过于复杂才选择J2EE的？因为它可以用简单的途径实现差不多的目标——软件的“二进制”重用、组件化、专业分工（容器开发商和应用开发商的分工）。事实上，你是被微软所抛弃的，同时，你也抛弃了微软。</p>
<p>　　现在让我们回来吧，我把你带进了COM的迷宫，现在让我把你领回来。再让我们看看COM到底想实现什么目标，其实很简单，不过是代码的二进制重用，也就是说你不必给别人源代码，而且你的组件可以象计算机硬件那样“即插即用”。我们回过头来看看Java，其实，这种二进制重用的困难是C++所带来的（这不是 C++本身的错，而是静态编译的错），当Java出现的时候，很多问题已经不存在了。你不需要一个头文件，因为Java的字节码是自解释的，它说明了自己是什么样子的，可以做什么事情。不像C++那样需要一个头文件来解释这些事情；也不需要事先了解对象的内存结构，因为内存是在运行的时候才分配的。如果我们现在再回过头来解决COM要解决的问题，你会怎么做呢？首先你会不再选择C++这种语言来实现代码的“二进制”重用，其次，你会把所有的语言编译成同样的“二进制”代码（实际上，应当说是字节码），这显然是更聪明的做法，从前COM试图在源代码的级别抹平二进制层次的差异，这实际上是让人在做本来应当由机器做的事情，很愚蠢是吗？但他们一直做了那么多年，而且把这个痛苦带给了整个计算机世界——因为他们掌握着事实的标准，为了用户，为了利润，为了能够在 Windows上运行，尽管你知道你在做着一个很不聪明的事情，但你还是做了。</p>
<p>　　COM技术为了照顾VB 这个小兄弟和实现统一二进制世界的野心，实在浪费了太多的精力。首先，落后的东西的消亡是必然的，就象C、Pascal在应用领域的消亡一样，Basic 一点一点的改良运动是不符合历史潮流的做法，先进的东西和落后的东西在一起，要么先进的东西被落后的东西拖住后腿，要么是同化落后的东西，显然我们更愿意看见后者，现在Basic终于被现代的计算机语言同化了。其次，统一二进制世界好像不是那么简单的事情，而且也没什么必要，微软的COM技术奋战了10 年，现在也只有他自己和Borland支持，.Net终于放弃了这个野心。这一切终于要结束了。</p>
<p>　　过去 J2EE高歌猛进地占领着应用开发的领地，COM在这种进攻面前多少显得苍白无力。现在微软终于也有了可以和J2EE一较长短的.NET，对于开发人员来讲，基于字节码的组件的二进制重用现在是天经地义的事情；你不用再为了能够以类方式发布组件做那么多乱七八糟的事情，因为现在所有的东西本来就是类了；实现软件开发的分工也很自然，你是专业人员，就用C#吧，你是应用开发人员，你喜欢用VB.Net，你就用吧，反正你们写的东西最终都被翻译成了一样的语言（其实我觉得这一点意义不大，因为一些不那么好用的语言被淘汰是正常的事情，C风格成为程序设计语言的主流风格，肯定是有它的原因的，语言的统一其实是大势所趋，就象中国人民都要说普通话一样，我觉得Java不支持多语言算不上缺点——本来就是一种很好看很好用的语言了，为什么要把简单问题复杂化呢？）。 COM不会在短期内死去，因为我估计微软还不会马上用C#开发Office和Windows的图形界面部分，但我相信COM技术退出历史舞台的日子已经不远了，作为一般的开发人员，忘了这段不愉快的历史吧——你将不会在你的世界里直接和COM打交道。若干年以后，我想COM也许会成为一场笑话，用来讽刺那种野心过大、钻牛角尖的愚蠢的聪明人。<br />
结论<br />
&lt;br /&gt;　　说了很多，应该是有个结论的时候了。我似乎做了一件冒天下之大不韪的事情，因为我评价了主流技术，还要试图进行比较，好像某个名人说过：“C++ Builder也好，Visual C++也好，能在市场上立足，肯定都是有自己的过人之处的，而且一个人精通数种开发语言、数种开发工具是不可能的事情”，言下之意就是说你不要对这些东西妄加评论，但怎么可以不评论？好像高手都不屑于说哪种语言好、哪种语言坏，我不知道什么时候形成了这种风气。简单地说C++比Java好或者Java比 C++好显然是愚蠢的行为，但如果让你用Java写驱动程序，用C++开发一个MIS系统是不是愚蠢的行为呢？显然更愚蠢。我想，作为一个独立的能思考的人，外界的东西对你而言总是有好有坏，而且你的生命有限，你还要享受你的生活，所以你必须做出选择。所以，起码评价这些东西对我自己而言是正确的——只要我有能力评价，那我就说出我的评价吧。</p>
<p>　　对于计算机语言来说，未来真正重要的语言只有三种C++、 Java和C#。C++将更适合于专业的计算机公司编写图形界面系统（比如KDE）、虚拟机（比如Java虚拟机或者.Net运行环境）、杀毒软件或者其他的盒装软件（比如说Photoshop、Dreamweaver）这一类的东西。而且C++适合程序员做学习之用，能对C++有一定理解的程序员往往也应该能更深刻的理解Java、C#，这有助于编写更好的软件。如果是开发为客户定制的应用系统Java、C#是更好的选择。包括桌面应用和Web应用。</p>
<p>　　至于其他的语言比如VB.Net其实并没有太大的意义。Delphi在未来一段时间将继续存在，而且活得不错。最重要的原因在于，第一它有一套丰富的组件库，第二它效率相对算高的，第三它简单。如果虚拟机的执行效率赶不上Delphi，它就有存在的理由，但从过去的Visual J++来看，微软的虚拟机做得确实可以很好，加上.Net的组件库和C#的简单性并不差，所以从长远来看Delphi可能不那么乐观。</p>
<p>　　其实上面的比较也包含了桌面应用程序框架的比较。在现在来说VCL无疑最好的，MFC已经退出历史舞台。.Net中所带的桌面应用程序框架将最终统一桌面应用领域（但不包括微软和Borland这样的专业公司，因为他们要作出最好用而且效率最高的软件）。至于Java中所带的桌面应用程序框架，实在让人哭笑不得。这个结论的变数是.Net运行环境的执行效率。如果.Net中的虚拟机象Java的一样，那微软就倒霉了，它等于放弃了桌面应用开发工具领域，但根据微软在Visual J++上的成就和他推广.Net的背水一战的驾式，.Net在桌面领域失败的可能性不大（但不是没有，起码基于COM的技术在企业应用领域几乎可以说是全军覆没）。</p>
<p>　　在企业应用程序框架领域，最终只有J2EE和.Net可以决一雌雄。我没有提到CORBA，它也可以算是企业应用程序框架，但他的声势和J2EE或者.NET实在不能同日而语，而且最重要的是只有Borland一家大公司支持它（SUN、 IBM、BEA、Borland支持J2EE，微软就不用说了），所以就不详细说他了。那么最终谁会赢呢？我想微软赢的可能性大一些。这样说可能让很多人不快，而且IBM的厉害也是有目共睹的。但这并不是纯技术问题，就象Windows NT蚕食Unix的领土那样，那时候微软也是孤军作战。J2EE的问题在于第一：混乱，第二，价高。我相信很多人都对这两点有过不快的经历。你知道写给 Weblogic的应用程序不是很顺利地就可以移植到Websphere上的，反过来也一样。但.Net就不一样了，那是微软一个人的作品，根本不存在移植的问题。</p>
<p>　　如果J2EE阵营不想败在这一点上，有三个办法，第一种就是通过制定统一的标准彻底消灭移植问题，第二种是开发一种好用的部署工具（不能象JBuilder那么大、那么慢：），屏蔽不同的应用程序容器之间的区别，第三种，也是最不可能的，就是 J2EE阵营有人能够一统天下。显然，这三种解决办法都不太现实。第二点价高，这是SUN、IBM、BEA、ORACLE传统，也是它们一直让微软的进攻屡屡得手的软肋。我一直不太能明白他们的西就为什么那么贵。这样想一想：微软的.Net SDK白送给你，BEA的Web logic一个CPU的License两万，如果你两种技术都会，如果你给客户的系统报价一样，你选哪种开发技术？这一点实在让人觉得无可奈何。J2EE 有的东西，.Net也有（除了不能跨平台），技术上的细微差别在巨大的价格差异面前还有什么意义呢？当然，SUM、IBM这些大公司也不是等闲之辈。就象 Windows NT没有消灭Unix一样，J2EE应当会像Windows NT和Unix的共存一样和.Net共存，只是我想.Net恐怕会占上风。</p>
<p>　　闲话</p>
<p>　　说完了该说的技术问题，说说闲话吧。有的话放在心里觉得不说出来不舒服，且让我一吐为快:)</p>
<p>　　给入门程序员的建议</p>
<p>　　不知道我在学计算机的时候是不是走了弯路。但我想如果让我重新开始学写程序的话，我会采用一些不同的办法。如果你也正在想成为一个程序员，这些也许会对你有帮助。我觉得可能大概要分几个阶段，第一个阶段应该是找一门简单的语言入门，比如Java或者C#都应该比较合适，选一本简单的带例子的书（最好不要太厚），按部就班的把书学完。这时候可能还有些懵懵懂懂，但没关系，可以开始做个小小的软件了，重要的事你要自己用那种语言的方式想思考，如果有项目做，当然更好。之后，你会觉得有点感觉了。如果你象我一样不是科班出身的，接下来应当补习一下计算机专业的课程，我觉得最重要的是数据结构——那些东西你可能永远都不会自己做，C++ 中有漂亮的STL，Java中也为你实现了大部分东西，但我觉得真的有必要学习那些内容，这会加强你用计算机语言思考问题的能力。在进一步，如果你的入门语言不是C++，那你可以补习一下C++，尽管你可能永远都不会用C++开发程序。C++在现在的计算机世界就象是普通话一样，而且它能让你很容易的理解其他语言中难以理解的问题。学完了C++，那你应当就已经不是一个初级程序员了，欢迎你进入计算机软件开发的世界。<br />
&lt;br /&gt;　　印度的软件业</p>
<p>　　我记得好像在CSDN上看见过一篇文章，极力的鼓吹印度的软件业。而且我记得他好像说过一句很刻薄的话“我们公司那些B大的和T大的，一个一个特别牛，牛得看不见人……做起界面极尽奇迹淫巧之能事……”，诸如此类，总之认为程序员只有象印度的高中生那样乖乖的、懂得UML、会看Function Specification才算是真正的程序员。我当时觉得很不舒服。我想这个人应该不是B或T大的——哦，别误会，我也不是——但我觉得好像B大的T大的人没象他说的那样。而且我不明白为什么中国的软件业为什么一定要向印度看齐？作为一家公司，你想获取商业利润，学习印度无可厚非，你大可以找一大堆高中生培训成编程蓝领（我没有轻视高中生的意思，我相信有很多“高中生”在技术领域取得的成就是让我望尘莫及的），但你不应该因此就把有血有肉有个性的程序员扁得一钱不值。说实话，所谓的编程蓝领不过是工厂里面的装配工，如果有一天工厂里面换了自动化的设备，这些人就全成了废人！而你要知道并不是这些装配工发明了自动化机器。我想这种话用不着多说，子曰“过犹不及”，你可以喜欢变成蓝领，但不要把问题推向极端，把问题推向极端往往就会犯错误。我们中国可以在某种程度上学习印度，但好像我们更应该学习美国——只是我们现在没那么富裕——可是微软也不是从一开始就是这样一个伟大的帝国的，IBM也一样</p>
<p>　　附录参考书目</p>
<p>　　阅读如下图书有助于理解本文内容。而且这些书都是好书，值得一读。</p>
<p>　　*《标准C++宝典》<br />
　　*《C++编程思想》<br />
　　*《深入浅出MFC2e》<br />
　　*《COM技术内幕》<br />
　　*《COM本质论》<br />
　　*《Java编程思想》<br />
　　*《精通EJB》第二版<br />
　　*《J2EE编程指南》<br />
　　*《Delphi6开发人员指南》<br />
　　*《C#宝典》<br />
　　*《微软.Net 战略》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xixis.net/archives/ainstream-development-technology.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

