<?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>SpongeLiu的blog</title>
	<atom:link href="http://www.spongeliu.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.spongeliu.com</link>
	<description>Love what you do!</description>
	<lastBuildDate>Tue, 24 Apr 2012 12:58:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>URL相似度计算的思考</title>
		<link>http://www.spongeliu.com/%e7%ae%97%e6%b3%95/url/</link>
		<comments>http://www.spongeliu.com/%e7%ae%97%e6%b3%95/url/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 12:58:23 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[其他]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[url相似度]]></category>
		<category><![CDATA[相似url]]></category>
		<category><![CDATA[相似度计算]]></category>
		<category><![CDATA[编辑距离]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=399</guid>
		<description><![CDATA[在做一些web相关的工作的时候，我们往往可能需要做一些对url的处理，其中包括对相似的url的识别和处理。这就需要计算两个url的相似度。

那么怎么进行url相似度的计算的？我首先想到的是把一个url看作是一个字符串，这样就简化成<span style="color: #ff0000;">两个字符串相似度</span>的计算。字符串相似度计算有很多已经比较成熟的算法，比如“<a href="http://en.wikipedia.org/wiki/Levenshtein_Distance">编辑距离算法</a>”，该算法描述了两个字符串之间转换需要的最小的编辑次数；还有一些其他的比如“<a href="http://www.cnblogs.com/dartagnan/archive/2011/10/06/2199764.html">最长公共字串</a>”等方法。但这些方法对于url相似度的计算来说是不是够了呢？比如给以下三个url：

url1: www.spongeliu.com/xxx/123.html
url2: www.spongeliu.com/xxx/456.html
url3: www.spongeliu.com/xxx/abc.html

这三个url的<span style="color: #ff0000;">编辑距离是一致</span>的，但是直观上我们却认为url1和url2更加相似一些。

再比如我们要判断两个站点是否同一套建站模版建立的，抽出两个url如下这样：
url1: www.163.com/go/artical/43432.html
url2: www.sina.com.cn/go/artical/453109.html

这两个url按照情景应该是相似的，这就超出了字符串相似度判断的能力范围。]]></description>
			<content:encoded><![CDATA[<p>在做一些web相关的工作的时候，我们往往可能需要做一些对url的处理，其中包括对相似的url的识别和处理。这就需要计算两个url的相似度。</p>
<p>那么怎么进行url相似度的计算的？我首先想到的是把一个url看作是一个字符串，这样就简化成<span style="color: #ff0000;">两个字符串相似度</span>的计算。字符串相似度计算有很多已经比较成熟的算法，比如“<a href="http://en.wikipedia.org/wiki/Levenshtein_Distance">编辑距离算法</a>”，该算法描述了两个字符串之间转换需要的最小的编辑次数；还有一些其他的比如“<a href="http://www.cnblogs.com/dartagnan/archive/2011/10/06/2199764.html">最长公共字串</a>”等方法。但这些方法对于url相似度的计算来说是不是够了呢？比如给以下三个url：</p>
<p>url1: www.spongeliu.com/xxx/123.html<br />
url2: www.spongeliu.com/xxx/456.html<br />
url3: www.spongeliu.com/xxx/abc.html</p>
<p>这三个url的<span style="color: #ff0000;">编辑距离是一致</span>的，但是直观上我们却认为url1和url2更加相似一些。</p>
<p>再比如我们要判断两个站点是否同一套建站模版建立的，抽出两个url如下这样：<br />
url1: www.163.com/go/artical/43432.html<br />
url2: www.sina.com.cn/go/artical/453109.html</p>
<p>这两个url按照情景应该是相似的，这就超出了字符串相似度判断的能力范围。</p>
<p>重新回到问题，要判断的是两个url的相似度，但是字符串的判断方法又不能很好应用。那么url和字符串的区别在哪里？<span style="color: #ff0000;">这取决于如何定义相似的url</span>。可以注意到，url比字符串含有更多的信息可以参考，因为url本身是包含<strong><span style="color: #ff0000;">结构和特征</span></strong>的，比如站点、目录。定义相似url的时候，是否要考虑站点？是否要考虑目录的一致？是否要考虑目录的深度？这取决于具体的需求。</p>
<p>考虑到url本身的结构，<span style="color: #ff0000;">对其相似度的计算就可以抽象为对其关键特征相似度的计算</span>。比如可以把站点抽象为一维特征，目录深度抽象为一维特征，一级目录、二级目录、尾部页面的名字也都可以抽象为一维特征。比如下面两个url:<br />
url1:  http://www.spongeliu.com/go/happy/1234.html<br />
url2:  http://www.spongeliu.com/snoopy/tree/abcd.html</p>
<p>先不定义他们是否相似，先来抽象一下他们的特征：</p>
<p>1、<span style="color: #0000ff;">站点特征</span>：如果两个url站点一样，则特征取值1，否则取值0；<br />
2、<span style="color: #0000ff;">目录深度特征</span>：特征取值分别是两个url的目录深度是否一致；<br />
3、<span style="color: #0000ff;">一级目录特征</span>：在这维特征的取值上，可以采用多种方法，比如如果一级目录名字相同则特征取1，否则取0；或者根据目录名字的编辑距离算出一个特征值；或者根据目录名字的pattern，如是否数字、是否字母、是否字母数字穿插等。这取决于具体需求，这里示例仅仅根据目录名是否相同取1和0；<br />
4、<span style="color: #0000ff;">尾页面特征</span>：这维特征的取值同一级目录，可以判断后缀是否相同、是否数字页、是否机器生成的随机字符串或者根据编辑长度来取值，具体也依赖于需求。这里示例仅仅判断最后一级目录的特征是否一致（比如是否都由数字组成、是否都有字母组成等）。</p>
<p>这样，对于这两个url就获得了4个维度的特征，分别是：1 1 0 0 。</p>
<p>有了这两个特征组合，就可以根据具体需求判断是否相似了。我们定义一下每个特征的重要程度，给出一个公式：</p>
<p>similarity = feather1 * x1 + feather2*x2 + feather3*x3 + feather4*x4;</p>
<p>其中x表示对应特征的重要程度，比如我认为站点和目录都不重要，最后尾页面的特征才是最重要的，那么x1,x2,x3都可以取值为0，x4取值为1，这样根据similarity就能得出是否相似了。或者认为站点的重要性占10%，目录深度占50%，尾页面的特征占40%，那么系数分别取值为0.1\0.5\0\0.4即可。</p>
<p>其实这样找出需要的特征，可以把这个问题<span style="color: #ff0000;">简化成一个机器学习的问题</span>，只需要人为判断出一批url是否相似，用svm训练一下就可以达到机器判断的目的。</p>
<p>除了上面这种两个url相似度的判断，<span style="color: #ff0000;">也可以将每一条url都抽象成一组特征，然后计算出一个url的得分，设置一个分数差的阈值，就可以达到从一大堆url中找出相似的url的目的</span>。</p>
<p>下面的代码是perl编写的抽象两个url特征的脚本，这只是一个测试的脚本，难免有bug和丑陋的地方，仅供参考：</p>

<div class="wp_syntax"><div class="code"><pre class="perl" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/usr/bin/perl</span>
<span style="color: #000000; font-weight: bold;">use</span> strict<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> warnings<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$url1</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$ARGV</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$url2</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$ARGV</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@array1</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/\//</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$url1</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@array2</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/\//</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$url2</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
<span style="color: #666666; font-style: italic;">#特征1：目录数</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$path1</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">@array1</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$path2</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">@array2</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#print $path1, $path2;</span>
<span style="color: #666666; font-style: italic;">#特征2：是否目录结尾</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$lastispath1</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$lastispath2</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$url1</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/\/$/</span> <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #0000ff;">$lastispath1</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$url1</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/\/$/</span> <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #0000ff;">$lastispath2</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #666666; font-style: italic;">#特征3：最后一级是否有后缀(htm,html,shtml等)</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$len</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$hassuffix1</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$hassuffix2</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$suffixstr</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$laststr1</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$array1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$path1</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$laststr2</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$array2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$path2</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$issuffixsame</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$lastispath1</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@suffix1</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/\./</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$array1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$path1</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">@suffix1</span> <span style="color: #339933;">&gt;=</span> <span style="color: #cc66cc;">2</span> <span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #0000ff;">$len</span> <span style="color: #339933;">=</span> <span style="color: #000066;">rindex</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$suffix1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@suffix1</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$len</span> <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">5</span> <span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$hassuffix1</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
			<span style="color: #0000ff;">$suffixstr</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$suffix1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@suffix1</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$tmplen</span> <span style="color: #339933;">=</span> <span style="color: #000066;">rindex</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$array1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@array1</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #0000ff;">$laststr1</span> <span style="color: #339933;">=</span> <span style="color: #000066;">substr</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$array1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@array1</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$tmplen</span><span style="color: #339933;">-</span><span style="color: #0000ff;">$len</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$lastispath2</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@suffix2</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/\./</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$array2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$path2</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">@suffix2</span> <span style="color: #339933;">&gt;=</span> <span style="color: #cc66cc;">2</span> <span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #0000ff;">$len</span> <span style="color: #339933;">=</span> <span style="color: #000066;">rindex</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$suffix2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@suffix2</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$len</span> <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">5</span> <span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$hassuffix2</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$suffixstr</span> <span style="color: #b1b100;">eq</span> <span style="color: #0000ff;">$suffix2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@suffix2</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#123;</span>
				<span style="color: #0000ff;">$issuffixsame</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
			<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$tmplen</span> <span style="color: #339933;">=</span> <span style="color: #000066;">rindex</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$array2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@array2</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\$</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #0000ff;">$laststr2</span> <span style="color: #339933;">=</span> <span style="color: #000066;">substr</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$array2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">@array2</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$tmplen</span><span style="color: #339933;">-</span><span style="color: #0000ff;">$len</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#特征3：最后一级几个分隔符(通过特征匹配计算laststr1和laststr2相似度，如果仅计算字符串相似度，可以用编辑长度)</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@area1</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/-/</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$laststr1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@area2</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/-/</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$laststr2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$j</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$totalarea1</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$totalarea2</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@patternarray1</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@patternarray2</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@splitarray1</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@splitarray2</span><span style="color: #339933;">=</span><span style="color: #009900;">&#123;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">#my $numarea1 = @area2;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#print $laststr1,&quot; &quot;,$laststr2,&quot;\n&quot;,$numarea1,&quot;\n&quot;;</span>
<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">&lt;=</span><span style="color: #0000ff;">@area1</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">++</span> <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@tmp1</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/_/</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$area1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$j</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$j</span><span style="color: #339933;">&lt;</span><span style="color: #0000ff;">@tmp1</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$j</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^\d+$/</span> <span style="color: #009900;">&#41;</span>	
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#数字pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">elsif</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^[a-zA-Z]+$/</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#纯字母pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">elsif</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^[a-zA-Z]+[0-9]+$/</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#先字母后数字pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">elsif</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^[0-9]+[a-zA-Z]+$/</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">4</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#先数字后字母pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">else</span> 
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#其他pattern</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$j</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$splitarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">else</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$splitarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #0000ff;">$totalarea1</span> <span style="color: #339933;">++;</span>
&nbsp;
	<span style="color: #009900;">&#125;</span>	
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">&lt;=</span><span style="color: #0000ff;">@area2</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">++</span> <span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@tmp2</span> <span style="color: #339933;">=</span> <span style="color: #000066;">split</span><span style="color: #009900;">&#40;</span> <span style="color: #009966; font-style: italic;">/_/</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$area2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$j</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$j</span><span style="color: #339933;">&lt;</span><span style="color: #0000ff;">@tmp2</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$j</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^\d+$/</span> <span style="color: #009900;">&#41;</span>	
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#数字pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">elsif</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^[a-zA-Z]+$/</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#纯字母pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">elsif</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^[a-zA-Z]+[0-9]+$/</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#先字母后数字pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">elsif</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tmp2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$j</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=~</span> <span style="color: #009966; font-style: italic;">/^[0-9]+[a-zA-Z]+$/</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">4</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#先数字后字母pattern</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">else</span> 
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$patternarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">#其他pattern</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$j</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$splitarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">else</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #0000ff;">$splitarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #0000ff;">$totalarea2</span> <span style="color: #339933;">++;</span>
&nbsp;
	<span style="color: #009900;">&#125;</span>	
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000066;">print</span> <span style="color: #0000ff;">$path1</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$lastispath1</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$hassuffix1</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$issuffixsame</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">&lt;</span><span style="color: #0000ff;">$totalarea1</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #000066;">print</span> <span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$splitarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$patternarray1</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000066;">print</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000066;">print</span> <span style="color: #0000ff;">$path2</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$lastispath2</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$hassuffix1</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$issuffixsame</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">&lt;</span><span style="color: #0000ff;">$totalarea2</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #000066;">print</span> <span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$splitarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot; &quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$patternarray2</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000066;">print</span> <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">#print @array1;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e7%ae%97%e6%b3%95/url/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C语言可变参数函数取参方法</title>
		<link>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/getargument/</link>
		<comments>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/getargument/#comments</comments>
		<pubDate>Sun, 26 Feb 2012 13:49:31 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[C语言]]></category>
		<category><![CDATA[语言学习]]></category>
		<category><![CDATA[printf]]></category>
		<category><![CDATA[参数传递]]></category>
		<category><![CDATA[变参]]></category>
		<category><![CDATA[可变参数函数]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=331</guid>
		<description><![CDATA[熟悉C的人都知道，C语言支持<span style="color: #ff0000;">可变参数函数(Variable Argument Functions)</span>，即参数的个数可以是不定个，在函数定义的时候用(...)表示，比如我们常用的printf()\execl函数等；printf函数的原型如下：
<pre lang="c">int printf(const char *format, ...);</pre>
<span style="color: #ff0000;">注意，采用这种形式定义的可变参数函数，至少需要一个普通的形参，比如上面代码中的*format，后面的省略号是函数原型的一部分。</span>

C语言之所以可以支持可变参数函数，一个重要的原因是<a href="http://www.spongeliu.com/linux/linuxstack/">C调用规范</a>中规定C语言函数调用时，参数是从右向左压入栈的；这样一个函数实现的时候，就无需关心调用他的函数会传递几个参数过来，而只要关心自己用到几个；以printf为例：
<pre lang="c">printf("%d%s\n",i,s);</pre>
printf函数在定义的时候，不知道函数调用的时候会传递几个参数。在实现上，printf函数只需关心第一个参数，即字符串“%d%s\n”，当读到%d的时候，printf知道自己需要第二个参数，这时只需要去栈上寻找即可；当读到%s时，再去栈上网上寻找一个参数即可。简单说，printf不关心栈上到底压了多少参数，只关心自己需要多少。

那么对于一个定义为可变参数的函数，函数定义的时候并没有定义形参原型，怎么使用参数呢？]]></description>
			<content:encoded><![CDATA[<p>熟悉C的人都知道，C语言支持<span style="color: #ff0000;">可变参数函数(Variable Argument Functions)</span>，即参数的个数可以是不定个，在函数定义的时候用(...)表示，比如我们常用的printf()\execl函数等；printf函数的原型如下：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>format<span style="color: #339933;">,</span> ...<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><span style="color: #ff0000;">注意，采用这种形式定义的可变参数函数，至少需要一个普通的形参，比如上面代码中的*format，后面的省略号是函数原型的一部分。</span></p>
<p>C语言之所以可以支持可变参数函数，一个重要的原因是<a href="http://www.spongeliu.com/linux/linuxstack/">C调用规范</a>中规定C语言函数调用时，参数是从右向左压入栈的；这样一个函数实现的时候，就无需关心调用他的函数会传递几个参数过来，而只要关心自己用到几个；以printf为例：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>i<span style="color: #339933;">,</span>s<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>printf函数在定义的时候，不知道函数调用的时候会传递几个参数。在实现上，printf函数只需关心第一个参数，即字符串“%d%s\n”，当读到%d的时候，printf知道自己需要第二个参数，这时只需要去栈上寻找即可；当读到%s时，再去栈上网上寻找一个参数即可。简单说，printf不关心栈上到底压了多少参数，只关心自己需要多少。</p>
<p>那么对于一个定义为可变参数的函数，函数定义的时候并没有定义形参原型，怎么使用参数呢？</p>
<p>C语言定义了一系列宏来完成可变参数函数参数的读取和使用：<span style="color: #ff0000;">宏va_start、va_arg和va_end</span>；在ANSI C标准下，这些宏定义在stdarg.h中。三个宏的原型如下：</pre>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> va_start<span style="color: #009900;">&#40;</span>va_list ap<span style="color: #339933;">,</span> last<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//取第一个可变参数（如上述printf中的i）的指针给ap，last是函数声明中的最后一个固定参数（比如printf函数原型中的*fromat）；</span>
type va_arg<span style="color: #009900;">&#40;</span>va_list ap<span style="color: #339933;">,</span> type<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//返回当前ap指向的可变参数的值，然后ap指向下一个可变参数；type表示当前可变参数的类型（支持的类型位int和double）；</span>
<span style="color: #993333;">void</span> va_end<span style="color: #009900;">&#40;</span>va_list ap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//将ap置为NULL</span></pre></div></div>

<p>当一个函数被定义位可变参数函数时，其函数体内首先要定义一个va_list的结构体类型，这里沿用原型中的名字，ap。</p>
<p>va_start使ap指向第一个可选参数。va_arg返回参数列表中的当前参数并使ap指向参数列表中的下一个参数。va_end把ap指针清为NULL。函数体内可以多次遍历这些参数，但是都必须以va_start开始，并以va_end结尾。</p>
<p>下面是一个具体的示例(摘自<a href="http://zh.wikipedia.org/wiki/%E5%8F%AF%E8%AE%8A%E5%8F%83%E6%95%B8%E5%87%BD%E6%95%B8">wikipedia</a>)：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdarg.h&gt;</span>
&nbsp;
<span style="color: #993333;">double</span> average<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> count<span style="color: #339933;">,</span> ...<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    va_list ap<span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> j<span style="color: #339933;">;</span>
    <span style="color: #993333;">double</span> tot <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    va_start<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span> count<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//使va_list指向起始的參數</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>j<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> j<span style="color: #339933;">&lt;</span>count<span style="color: #339933;">;</span> j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
        tot<span style="color: #339933;">+=</span>va_arg<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span> <span style="color: #993333;">double</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//檢索參數，必須按需要指定類型</span>
    va_end<span style="color: #009900;">&#40;</span>ap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//釋放va_list</span>
    <span style="color: #b1b100;">return</span> tot<span style="color: #339933;">/</span>count<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>除此之外，<span style="color: #ff0000;">我们还需要注意一个陷阱，即va_arg宏的第2个参数不能被指定为char、short或者float类型。《<a href="http://click.union.360buy.com/JdClick/?unionId=23843&amp;t=4&amp;to=http://www.360buy.com/product/10062654.html" target="_blank">C和C++经典著作：C陷阱与缺陷</a>》</span>在可变参数函数传递时，因为char和short类型的参数会被提升为int类型，而float类型的参数会被提升为double类型 。</p>
<p>例如，以下的代码是错误的</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">a <span style="color: #339933;">=</span> va_arg<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span><span style="color: #993333;">char</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>因为我们无法传递一个char类型参数，如果传递了，它将会被自动转化为int类型。上面的式子应该写成：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">a <span style="color: #339933;">=</span> va_arg<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span><span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>还需要注意的一个问题是，即时我们知道在某种体系结构下C语言函数的参数都压在栈上，我们也应该避免直接去栈上取想要的参数，因为这样会降低程序的灵活性和可移植性，并带来一些安全上潜在的危险。上述的三个宏，包括va_list，在不同的体系结构下会有不同的实现方法，比如va_list，有的系统上直接指向栈；而有的系统却将其实现为一个指针数组。</p>
<p>参考资料：<br />
《<a href="http://click.union.360buy.com/JdClick/?unionId=23843&#038;t=4&#038;to=http://www.360buy.com/product/10062360.html" target="_blank">UNIX环境高级编程（第2版）</a>》<br />
《<a href="http://click.union.360buy.com/JdClick/?unionId=23843&#038;t=4&#038;to=http://www.360buy.com/product/10062654.html" target="_blank">C和C++经典著作：C陷阱与缺陷</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/getargument/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>弱类型？C语言参数提升带来的一个陷阱</title>
		<link>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/ctypetransfer/</link>
		<comments>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/ctypetransfer/#comments</comments>
		<pubDate>Fri, 24 Feb 2012 16:32:04 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[C语言]]></category>
		<category><![CDATA[语言学习]]></category>
		<category><![CDATA[C99 弱类型 整数提升 参数提升]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=325</guid>
		<description><![CDATA[很久以前，我接触的最初几本C语言书中，我记得有类似这么一句话“<span style="color: #339966;">C语言是一种弱类型的语言，类型之间可以进行隐式的转换；而C++是强类型的语言，需要进行强制类型转换</span>”。我忘了是哪本书，但这句话我一直记得。因为实际写代码中一直也没有触碰隐式的转换（我一般都会强制转换），所以也没有深究过这个问题。然而最近的一段代码却给我带来了一些困惑。
<span style="color: #ffffff;">copyright@ www.spongeliu.com</span>
先抛开我遇到的问题不说，简单回顾下C语言的<span style="color: #ff0000;">隐式类型转换</span>，如下一段代码：
<pre lang="c">
#include <stdio.h>
double sum(double x, double y); //声明一个函数

int main()
{
    int x=10;
    int y=10;

    double z=sum(x,y);
    printf("%lf\n",z);
    return 0
}


</pre>
没问题，我们得到的结果是20.000000。]]></description>
			<content:encoded><![CDATA[<p>很久以前，我接触的最初几本C语言书中，我记得有类似这么一句话“<span style="color: #339966;">C语言是一种弱类型的语言，类型之间可以进行隐式的转换；而C++是强类型的语言，需要进行强制类型转换</span>”。我忘了是哪本书，但这句话我一直记得。因为实际写代码中一直也没有触碰隐式的转换（我一般都会强制转换），所以也没有深究过这个问题。然而最近的一段代码却给我带来了一些困惑。<br />
<span style="color: #ffffff;">copyright@ www.spongeliu.com</span><br />
先抛开我遇到的问题不说，简单回顾下C语言的<span style="color: #ff0000;">隐式类型转换</span>，如下一段代码：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #993333;">double</span> sum<span style="color: #009900;">&#40;</span><span style="color: #993333;">double</span> x<span style="color: #339933;">,</span> <span style="color: #993333;">double</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//声明一个函数</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> x<span style="color: #339933;">=</span><span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> y<span style="color: #339933;">=</span><span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #993333;">double</span> z<span style="color: #339933;">=</span>sum<span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span>y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%lf<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>z<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>没问题，我们得到的结果是20.000000。</p>
<p>同时，上面代码中，首先声明了sum函数的原型“double sum(double x,double y);”。 熟悉C的人都知道，在“old style c”中，<span style="color: #ff0000;">我们可以声明一个不带参数原型的函数</span>，也就是这么声明“double sum()；” 这表示sum函数可能有无限个参数，具体由函数定义来决定。那么，如果在上述代码中使用这种方式会怎么样呢？</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">double</span> sum<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//声明一个函数</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> x<span style="color: #339933;">=</span><span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> y<span style="color: #339933;">=</span><span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #993333;">double</span> z<span style="color: #339933;">=</span>sum<span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span>y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%lf<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>z<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>由于各个编译器的具体实现不同，我的实验环境是<span style="color: #ff0000;">Linux+gcc4.4.5</span>。在这样的编译环境下，你会发现<span style="color: #ff0000;">程序得到了一个不确定的值</span>！</p>
<p>很显然，这段代码跳入了一个陷阱。即时你在编译的时候加入了-Wall选项，也不会出现任何的警告！C既然允许我们声明一个参数未定义的函数原型，却为什么不让我们得到一个正确的程序呢？</p>
<p>让我们来看<a href="http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf">C99标准</a>中section 6.5.2.2 "Function calls" 的Paragraphs 6, 7：</p>
<p>Paragraphs6<br />
1、<span style="color: #ff0000;"><strong>默认参数提升</strong></span>：如果一个函数的形参类型未知，那么调用函数时要对相应的实参做“整数提升(integer promotions)”，除此以外，float类型的参数会被提升为double。<br />
2、如果形参和实参个数不相等的时候，行为未定义；<br />
3、 如果函数定义的时候指定参数原型，那么a)参数原型包含（...），即变参；b)形参类型和实参类型不符合。这两种行为都是未定义的;<br />
4、 如果函数定义的时候不指定参数原型，如果提升后的实参类型和形参类型不相符，则行为未定义；除了两种情况a)提升后一个是unsigned int一个是signed int，则值可以被表示成这两种的任何形式;b)实参或形参都是指针，分别指向限定和非限定（如const）的char或者void。</p>
<p>Paragraphs7<br />
1、 如果一个函数的形参类型已知，则实参的类型会被隐式的转换成形参的类型，并且转换成非限定的对应类型；<br />
2、如果函数原型中有(...)参数，那么对应的实参会被进行默认参数提升；</p>
<p>（以上纯属个人翻译，如想看原文，请参照<a href="http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf">c99标准手册</a>）</p>
<p>你也许会稍许有些疑惑，<span style="color: #ff0000;">什么情况下函数定义会没有原型（参数类型未知）</span>呢？让我们来看一下：</p>
<p>首先，<span style="color: #ff0000;">无论函数声明还是函数定义，都是可以没有原型的</span>。如这样的代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> func<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> a<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> b<span style="color: #339933;">,</span> <span style="color: #993333;">float</span> c<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">void</span> func<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> a<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> b<span style="color: #339933;">,</span> <span style="color: #993333;">float</span> c<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #808080; font-style: italic;">/* ... */</span> <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>line1是带参数原型的函数声明；line2是带参数原型的函数定义。</p>
<p>再看这样的代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> func<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">void</span> func<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> b<span style="color: #339933;">,</span> c<span style="color: #009900;">&#41;</span>
    <span style="color: #993333;">int</span> a<span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> b<span style="color: #339933;">;</span>
    <span style="color: #993333;">float</span> c<span style="color: #339933;">;</span>
<span style="color: #009900;">&#123;</span> <span style="color: #808080; font-style: italic;">/* ... */</span> <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>line1是不带参数原型的函数声明；line2往后是不带参数原型的函数定义 <span style="color: #ff0000;">(K&amp;R C style)</span>。</p>
<p><strong><span style="color: #ff0000;">简单来说，以上标准可以归结为两点：</span></strong></p>
<p>1、对于有参数原型的函数（非变参），实参会被隐式转换成相应的实参的类型；</p>
<p>2、对于没有参数原型的函数或者变参函数，实参会被进行“默认参数提升”</p>
<p>那现在来看，<span style="color: #ff0000;">我们之前的问题出再哪里了？首先，sum函数声明的时候没有定义参数原型，因此main函数在调用sum的时候，对参数作了int类型的提升，而不是隐式的转换；其次，sum函数在定义的时候指定了参数的类型，其类型同提升后得到的int类型不相同，命中标准中Paragraphs6的第三条，得到一个未定义的行为</span>，至于怎么处理，那就是编译器的事情了。</p>
<p>C语言的类型转换，除了上述的这些标准，还涉及到很多很复杂的事情，比如有符号、无符号、浮点等，每一种类型转换都要定义一种转换规则，而且不同的编译器不同的体系结构往往会带来不同的结果，<span style="color: #ff0000;">很多类型转换都是C标准中未定义的，很可能就导致错误的出现</span>。比如上述的这个例子，很显然是一个很阴暗的用法，我们在实际写程序的时候往往不会这么用，但是很不巧，我的一个程序中的一个函数参数很多，我在声明该函数的时候就偷懒没有指定参数的原型，而恰巧其中一个参数被作了提升而类型同函数定义的不一样，导致程序出错。因此，在C语言中，我们要尽量的避免使用隐式的类型转换。</p>
<p>此外<span style="color: #ff0000;">，对于文章开头提到的“C语言是弱类型”，实在不敢苟同</span>。其实争论一个语言是强弱类型本身就没有意义，但我个人认为，C语言这种在编译时就已经确定了数据类型的语言，如果硬要划分的话，怎么也不应该算是一个弱类型！</p>
<p>参考数目：<br />
<a href="http://click.union.360buy.com/JdClick/?unionId=23843&#038;t=4&#038;to=http://www.360buy.com/product/10062654.html" target="_blank">C和C++经典著作：C陷阱与缺陷</a><br />
<a href="http://click.union.360buy.com/JdClick/?unionId=23843&#038;t=4&#038;to=http://www.360buy.com/product/10063215.html" target="_blank">你必须知道的495个C语言问题</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/ctypetransfer/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>一个十分有趣的字符串算法题目</title>
		<link>http://www.spongeliu.com/%e7%ae%97%e6%b3%95/findstring/</link>
		<comments>http://www.spongeliu.com/%e7%ae%97%e6%b3%95/findstring/#comments</comments>
		<pubDate>Tue, 19 Apr 2011 09:21:39 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[算法]]></category>
		<category><![CDATA[blogspot]]></category>
		<category><![CDATA[字符串]]></category>
		<category><![CDATA[有趣的算法]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=278</guid>
		<description><![CDATA[在blogspot上看到一个十分有趣的字符串算法题目，原文在这里。作者讲述了自己面试google的一次经历。本文不理会这个故事，只来讨论一下里面着个有趣的算法。

算法题目：有两个字符串由不同的字母组成，一长一短，长的为A短的为B。设计一个算法，如果所有在B中出现的字符都在A中出现，则返回true，否则返回false。
例子：

如下字符串：

字符串A: abddfdioegdddffsfagj
字符串B: dofsjadg

字符串B中每个字符都在A中出现，返回true。

如下字符串：

字符串A: aaaabbbbbbdddddd
字符串B: acc

字符串B中有字符没在A中出现，返回false。
]]></description>
			<content:encoded><![CDATA[<p>在blogspot上看到一个十分有趣的字符串算法题目，原文在<a href="http://paultyma.blogspot.com/2010/11/google-interviewing-story.html">这里</a>。作者讲述了自己面试google的一次经历。本文不理会这个故事，只来讨论一下里面着个有趣的算法。</p>
<p><span style="color: #ff0000;">算法题目：</span>有两个字符串由不同的字母组成，一长一短，长的为A短的为B。设计一个算法，如果所有在B中出现的字符都在A中出现，则返回true，否则返回false。<br />
<span style="color: #ff0000;">例子： </span></p>
<p><span style="color: #0000ff;">如下字符串：</span></p>
<p>字符串A: abddfdioegdddffsfagj<br />
字符串B: dofsjadg</p>
<p><span style="color: #0000ff;">字符串B中每个字符都在A中出现，返回true。</span></p>
<p><span style="color: #0000ff;">如下字符串：</span></p>
<p>字符串A: aaaabbbbbbdddddd<br />
字符串B: acc</p>
<p><span style="color: #0000ff;">字符串B中有字符没在A中出现，返回false。</span></p>
<p>这只是个很基础的算法题目，相信很多人都能够立刻想出答案。</p>
<p><span style="color: #ff0000;">答案1</span>：对字符串B中的每个字母在A中都遍历一遍。这个答案很烂，其时间复杂度为O(n*m)</p>
<p><span style="color: #ff0000;">答案2</span>：设一个哈希表，对字符串A的字符遍历，将每个字符对应的哈希表中的值设为1。然后对B中的字符进行遍历，如果所有字符对应的hash值都为1，则返回true，否则返回false。</p>
<p>这个答案的时间复杂度是<span style="color: #ff0000;">O(m+n)</span>，应该是大多数面试者想要的答案，相信大多数人也能想到。<span style="color: #ff0000;">这样结束了</span>？如果真结束了，那就谈不上有趣了！如果我们<span style="color: #ff0000;">对空间要求比较高该怎么办</span>？</p>
<p><span style="color: #ff0000;">答案3</span>：我们可以观察到，字母总共就有26个，而且在上面答案中，hash表的值只有1和0两种情况。那就好办了，我们知道int类型是32位，如果用1位(bit)来表示一个字母是否出现，那么只需1个int类型就能够表示所有的字母了。</p>
<p>答案3实际上跟答案2类似，换汤不换药。有趣的不是他，<span style="color: #ff0000;">实际上还存在一种更有意思的方法</span>：</p>
<p><span style="color: #ff0000;">答案4</span>：<span style="color: #0000ff;">我们为每个字母(假设字母的数量是一定的)分配一个不重复素数，比如a为2， b为3， c为5，以此类推。这样在对字符串A进行遍历时，将每个字符表示的素数相乘，最终得到一个比较大的整数。然后从字符串B中第一个字母开始，用每个字母所代表的数除这个整数，如果余数不为0，那么就返回false。如果整个遍历过程中都没有余数，则返回true。</span></p>
<p>在我第一次从原文中看到着个答案的时候，有一种眼前一亮的感觉。实际上仔细推敲，这种算法的效率并不一定比之前的答案要高，因为往往一个乘法/除法的效率要小于加减法或者比较运算。但是却给出了一种全新的考虑问题的角度，有种奇思妙想的感觉！这种方法更为巧妙，有趣！</p>
<p>在每个算法题目中，你在得到一个公认的比较有效的方法后，是否考虑过更简单、有趣的方法呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e7%ae%97%e6%b3%95/findstring/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>再一次安装gentoo过程中遇到的几个小问题</title>
		<link>http://www.spongeliu.com/%e5%ba%94%e7%94%a8%e9%97%ae%e9%a2%98/gentoo/gentoo_reinstall/</link>
		<comments>http://www.spongeliu.com/%e5%ba%94%e7%94%a8%e9%97%ae%e9%a2%98/gentoo/gentoo_reinstall/#comments</comments>
		<pubDate>Fri, 04 Mar 2011 15:44:52 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[应用问题]]></category>
		<category><![CDATA[Error 65280]]></category>
		<category><![CDATA[imagemagick]]></category>
		<category><![CDATA[openoffice]]></category>
		<category><![CDATA[问题]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=266</guid>
		<description><![CDATA[<strong>1、<span style="color: #ff0000;">在安装openoffice过程中出现大致如下的错误</span></strong>
<pre lang="shell">ERROR: Error 65280 occurred while making /var/tmp/portage/app-office/openoffice-3.2.1-r1/work/ooo/build/OOO320_m19/desktop/zipintro 
rmdir /var/tmp/portage/app-office/openoffice-3.2.1-r1/temp/yERj5YXC9A 
make: *** [stamp/build] Error 1 
* ERROR: app-office/openoffice-3.2.1-r1 failed: 
* Build failed 
* 
* Call stack: 
* ebuild.sh, line 54: Called src_compile 
* environment, line 8141: Called die 
* The specific snippet of code: 
* make &#124;&#124; die "Build failed" 
* 
* If you need support, post the output of 'emerge --info =app-office/openoffice-3.2.1-r1', 
* the complete build log and the output of 'emerge -pqv =app-office/openoffice-3.2.1-r1'. 
!!! When you file a bug report, please include the following information: 
GENTOO_VM=sun-jdk-1.6 CLASSPATH="" JAVA_HOME="/opt/sun-jdk-1.6.0.22" 
JAVACFLAGS="-source 1.5 -target 1.5" COMPILER="" 
and of course, the output of emerge --info 
* The complete build log is located at '/var/log/portage/app-office:openoffice-3.2.1-r1:20101120-141010.log'. 
* The ebuild environment file is located at '/var/tmp/portage/app-office/openoffice-3.2.1-r1/temp/environment'. 
* S: '/var/tmp/portage/app-office/openoffice-3.2.1-r1/work/ooo' 

>>> Failed to emerge app-office/openoffice-3.2.1-r1, Log file: 

>>> '/var/log/portage/app-office:openoffice-3.2.1-r1:20101120-141010.log' 
</pre>

<strong>问题原因：</strong>openoffice依赖一个包imagemagick，该包编译时需要png。具体机制不详

<span style="color: #ff0000;">解决方法：</span>  USE="png"       emerge -av imagemagick openoffice
]]></description>
			<content:encoded><![CDATA[<p><strong>1、<span style="color: #ff0000;">在安装openoffice过程中出现大致如下的错误</span></strong></p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">ERROR: Error 65280 occurred while making /var/tmp/portage/app-office/openoffice-3.2.1-r1/work/ooo/build/OOO320_m19/desktop/zipintro 
rmdir /var/tmp/portage/app-office/openoffice-3.2.1-r1/temp/yERj5YXC9A 
make: *** [stamp/build] Error 1 
* ERROR: app-office/openoffice-3.2.1-r1 failed: 
* Build failed 
* 
* Call stack: 
* ebuild.sh, line 54: Called src_compile 
* environment, line 8141: Called die 
* The specific snippet of code: 
* make || die &quot;Build failed&quot; 
* 
* If you need support, post the output of 'emerge --info =app-office/openoffice-3.2.1-r1', 
* the complete build log and the output of 'emerge -pqv =app-office/openoffice-3.2.1-r1'. 
!!! When you file a bug report, please include the following information: 
GENTOO_VM=sun-jdk-1.6 CLASSPATH=&quot;&quot; JAVA_HOME=&quot;/opt/sun-jdk-1.6.0.22&quot; 
JAVACFLAGS=&quot;-source 1.5 -target 1.5&quot; COMPILER=&quot;&quot; 
and of course, the output of emerge --info 
* The complete build log is located at '/var/log/portage/app-office:openoffice-3.2.1-r1:20101120-141010.log'. 
* The ebuild environment file is located at '/var/tmp/portage/app-office/openoffice-3.2.1-r1/temp/environment'. 
* S: '/var/tmp/portage/app-office/openoffice-3.2.1-r1/work/ooo' 
&nbsp;
&gt;&gt;&gt; Failed to emerge app-office/openoffice-3.2.1-r1, Log file: 
&nbsp;
&gt;&gt;&gt; '/var/log/portage/app-office:openoffice-3.2.1-r1:20101120-141010.log'</pre></div></div>

<p><strong>问题原因：</strong>openoffice依赖一个包imagemagick，该包编译时需要png。具体机制不详</p>
<p><span style="color: #ff0000;">解决方法：</span>  USE="png"       emerge -av imagemagick openoffice</p>
<p><strong>2、<span style="color: #ff0000;">在root下面无法启动gedit等gui软件</span></strong><br />
错误提示为：</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">(gedit:5278): EggSMClient-WARNING **: Failed to connect to the session manager: None of the authentication protocols specified are supported 
&nbsp;
** 
GLib-GIO:ERROR:gdbusconnection.c:2271:initable_init: assertion failed: (connection-&gt;initialization_error == NULL) 
Aborted</pre></div></div>

<p><strong>问题原因：</strong>su进入root后，只是简单的切换user，并不能提供一个全root的运行环境<br />
<span style="color: #ff0000;">解决方法：</span>  使用 su - 代替 su。 注意su和-之间有个空格。</p>
<p><strong>3、<span style="color: #ff0000;">firefox字体模糊</span></strong><br />
<strong>问题原因：</strong>系统开启了抗锯齿效果<br />
<span style="color: #ff0000;">解决方法：</span>  在/etc/fonts/fonts.conf文件中添加：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;match</span> <span style="color: #000066;">target</span>=<span style="color: #ff0000;">&quot;font&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;test</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;family&quot;</span> <span style="color: #000066;">compare</span>=<span style="color: #ff0000;">&quot;eq&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>SimSun<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>&quot;or&quot;
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Bitstream Cyberbit<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>&quot;or&quot;
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>AR PL KaitiM Big5<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>&quot;or&quot;
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>AR PL Mingti2L Big5<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>&quot;or&quot;
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>AR PL KaitiM GB<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>&quot;or&quot;
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>AR PL SungtiL GB<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/test<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;edit</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;hinting&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;assign&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/edit<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;edit</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;autohint&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;assign&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/edit<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;edit</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;antialias&quot;</span> <span style="color: #000066;">mode</span>=<span style="color: #ff0000;">&quot;assign&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
                        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>false<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bool<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/edit<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/match<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p><strong>4、<span style="color: #ff0000;">在安装klibc过程中出现大致如下的错误</span></strong></p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;"> * Applying klibc-1.5.11-x86_64-io.h-return.diff ...                                                                                                            [ ok ] 
&gt;&gt;&gt; Source unpacked in /var/tmp/portage/dev-libs/klibc-1.5.15-r1/work 
&gt;&gt;&gt; Compiling source in /var/tmp/portage/dev-libs/klibc-1.5.15-r1/work/klibc-1.5.15 ... 
make -j3 defconfig CC=x86_64-pc-linux-gnu-gcc HOSTCC=x86_64-pc-linux-gnu-gcc 
Makefile:434: *** mixed implicit and normal rules.  Stop. 
emake failed 
 * ERROR: dev-libs/klibc-1.5.15-r1 failed: 
 *   No defconfig 
 * 
 * Call stack: 
 *     ebuild.sh, line  56:  Called src_compile 
 *   environment, line 2425:  Called die 
 * The specific snippet of code: 
 *       emake ${defconfig} CC=&quot;${CC}&quot; HOSTCC=&quot;${HOSTCC}&quot; || die &quot;No defconfig&quot;; 
 * 
 * If you need support, post the output of 'emerge --info =dev-libs/klibc-1.5.15-r1', 
 * the complete build log and the output of 'emerge -pqv =dev-libs/klibc-1.5.15-r1'. 
 * The complete build log is located at '/var/tmp/portage/dev-libs/klibc-1.5.15-r1/temp/build.log'. 
 * The ebuild environment file is located at '/var/tmp/portage/dev-libs/klibc-1.5.15-r1/temp/environment'. 
 * S: '/var/tmp/portage/dev-libs/klibc-1.5.15-r1/work/klibc-1.5.15' 
&nbsp;
&gt;&gt;&gt; Failed to emerge dev-libs/klibc-1.5.15-r1, Log file: 
&nbsp;
&gt;&gt;&gt;  '/var/tmp/portage/dev-libs/klibc-1.5.15-r1/temp/build.log' 
&nbsp;
 * Messages for package dev-libs/klibc-1.5.15-r1: 
&nbsp;
 * ERROR: dev-libs/klibc-1.5.15-r1 failed: 
 *   No defconfig 
 * 
 * Call stack: 
 *     ebuild.sh, line  56:  Called src_compile 
 *   environment, line 2425:  Called die 
 * The specific snippet of code: 
 *       emake ${defconfig} CC=&quot;${CC}&quot; HOSTCC=&quot;${HOSTCC}&quot; || die &quot;No defconfig&quot;; 
 * 
 * If you need support, post the output of 'emerge --info =dev-libs/klibc-1.5.15-r1', 
 * the complete build log and the output of 'emerge -pqv =dev-libs/klibc-1.5.15-r1'. 
 * The complete build log is located at '/var/tmp/portage/dev-libs/klibc-1.5.15-r1/temp/build.log'. 
 * The ebuild environment file is located at '/var/tmp/portage/dev-libs/klibc-1.5.15-r1/temp/environment'. 
 * S: '/var/tmp/portage/dev-libs/klibc-1.5.15-r1/work/klibc-1.5.15'</pre></div></div>

<p><strong>问题原因：</strong>高版本make的一个bug<br />
<span style="color: #ff0000;">解决方法：</span>  编译klibc的时候先将make版本降低</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">emerge --oneshot =make-3.80-r4 
emerge --oneshot klibc</pre></div></div>

<p>编译完成后再将版本升级回来</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">emerge --update --oneshot make</pre></div></div>

<p>参考：</p>
<p>http://forums.gentoo.org/viewtopic-t-849190.html?sid=d33383354a919e3ebabba9b36edd2d4e</p>
<p>http://bugs.gentoo.org/345743</p>
<p>http://forums.fedoraforum.org/archive/index.php/t-255624.html</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e5%ba%94%e7%94%a8%e9%97%ae%e9%a2%98/gentoo/gentoo_reinstall/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>为什么C++中空类和空结构体大小为1？</title>
		<link>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/why-not-null/</link>
		<comments>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/why-not-null/#comments</comments>
		<pubDate>Wed, 17 Nov 2010 14:40:53 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[C语言]]></category>
		<category><![CDATA[语言学习]]></category>
		<category><![CDATA[sizeof]]></category>
		<category><![CDATA[空类大小]]></category>
		<category><![CDATA[空结构体]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=260</guid>
		<description><![CDATA[这篇文章是一篇<span style="color: #ff0000;">译文</span>，跟<a href="http://www.spongeliu.com/clanguage/sizeof/">上一篇文章</a>相呼应的，原文在<a href="http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a">这里</a>。

对于结构体和空类大小是1这个问题，首先<span style="color: #ff0000;">这是一个C++问题</span>，在C语言下空结构体大小为0(当然这是编译器相关的)。这里的空类和空结构体是指类或结构体中没有任何成员。

<span style="color: #ff0000;">在C++下，空类和空结构体的大小是1</span>（编译器相关），这是为什么呢？为什么不是0？

这是因为，C++标准中规定，“<span style="color: #ff0000;">no object shall have the same address in memory as any other variable</span>” ，就是<span style="color: #ff0000;">任何不同的对象不能拥有相同的内存地址。</span> 如果空类大小为0，若我们声明一个这个类的对象数组，那么数组中的每个对象都拥有了相同的地址，这显然是违背标准的。

但是，也许你还有一个疑问，<span style="color: #ff0000;">为什么C++标准中会有这么无聊的规定呢？</span>]]></description>
			<content:encoded><![CDATA[<p>这篇文章是一篇<span style="color: #ff0000;">译文</span>，跟<a href="http://www.spongeliu.com/clanguage/sizeof/">上一篇文章</a>相呼应的，原文在<a href="http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a">这里</a>。</p>
<p>对于结构体和空类大小是1这个问题，首先<span style="color: #ff0000;">这是一个C++问题</span>，在C语言下空结构体大小为0(当然这是编译器相关的)。这里的空类和空结构体是指类或结构体中没有任何成员。</p>
<p><span style="color: #ff0000;">在C++下，空类和空结构体的大小是1</span>（编译器相关），这是为什么呢？为什么不是0？</p>
<p>这是因为，C++标准中规定，“<span style="color: #ff0000;">no object shall have the same address in memory as any other variable</span>” ，就是<span style="color: #ff0000;">任何不同的对象不能拥有相同的内存地址。</span> 如果空类大小为0，若我们声明一个这个类的对象数组，那么数组中的每个对象都拥有了相同的地址，这显然是违背标准的。</p>
<p>但是，也许你还有一个疑问，<span style="color: #ff0000;">为什么C++标准中会有这么无聊的规定呢？</span></p>
<p>当然，这样规定显然是有原因的。我们假设C++中有一个类型T，我们声明一个类型T的数组，然后再声明一个T类型的指针指向数组中间某个元素，则我们将指针减去1，应该得到数组的另一个索引。如下代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="c" style="font-family:monospace;">T array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> diff <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// diff = 1</span></pre></td></tr></table></div>

<p>上面的代码是一种指针运算，将两个指针相减，编译器作出如下面式子所示的动作：</p>
<p><span style="color: #ff0000;">diff = ((char *)&amp;array[3] - (char *)&amp;array[2]) / sizeof T;</span></p>
<p>式子应该不难懂把，很明显的一点就是这个式子的计算依赖于sizeof T。虽然上面只是一个例子，但是<span style="color: #ff0000;">基本上所有的指针运算都依赖于sizeof T。</span></p>
<p>好，下面我们来看，如果允许不同的对象有相同的地址将会引发什么样的问题，看下面的例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="c" style="font-family:monospace;"> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span>
                       <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span>
                       <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span>
                       <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span></pre></td></tr></table></div>

<p>我们可以看到，在这个例子中，如果每个对象都拥有相同地址，我们将没有办法通过指针运算来区分不同的对象。还有一个更严重的问题，就是如果 sizeof T是0，就会<span style="color: #ff0000;">导致编译器产生一个除0的操作</span>，引发不可控的错误。</p>
<p>基于这个原因，如果允许结构体或者类的大小为0，编译器就需要实现一些复杂的代码来处理这些异常的指针运算。</p>
<p>所以，C++标准规定不同的对象不能拥有相同的地址。那么怎样才能保证这个条件被满足呢？最简单的方法莫过于不允许任何类型的大小为0。所以编译器为每个空类或者空结构体都增加了一个虚设的字节（有的编译器可能加的更多），这样这些空类和空结构的大小就不会是0，就可以保证他们的对象拥有彼此独立的地址。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/why-not-null/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>c关键字－sizeof的种种</title>
		<link>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/sizeof/</link>
		<comments>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/sizeof/#comments</comments>
		<pubDate>Sun, 14 Nov 2010 07:02:48 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[C语言]]></category>
		<category><![CDATA[语言学习]]></category>
		<category><![CDATA[enum]]></category>
		<category><![CDATA[sizeof]]></category>
		<category><![CDATA[空类]]></category>
		<category><![CDATA[空结构体]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=250</guid>
		<description><![CDATA[熟悉c的人都知道，sizeof是一个关键字而不是一个宏或者库函数什么的，他的值是在编译时确定的，如果这个不了解，可以现看看<a href="http://www.spongeliu.com/clanguage/ckeyword/">这篇文章</a>和<a href="http://www.spongeliu.com/clanguage/sizeof-struct/">这篇文章</a>。

既然如此，让我们先看下面几个小例子：
<pre lang="c">sizeof(int);
sizeof(char);
sizeof(double);</pre>
上面三行sizeof的值是多少呢？这里我们假定在32位的x86系统下。<span style="color: #ff0000;">我们会得到答案：4，1，8</span>。这个没什么吧，大多数人都应该知道。那么，下面这个：
<pre lang="c">sizeof(int);
sizeof(long);</pre>
在32位x86下，这两个是多少呢？4，8？<span style="color: #ff0000;">实际上，答案是4，4</span>。我们需要注意，long类型在32位系统下是32位的。那么，64位下结果又如何呢？8，8？<span style="color: #ff0000;">其实答案是4，8</span>。另一个需要注意的是，<span style="color: #ff0000;">64位下的int是32位的</span>。]]></description>
			<content:encoded><![CDATA[<p>熟悉c的人都知道，sizeof是一个关键字而不是一个宏或者库函数什么的，他的值是在编译时确定的，如果这个不了解，可以现看看<a href="http://www.spongeliu.com/clanguage/ckeyword/">这篇文章</a>和<a href="http://www.spongeliu.com/clanguage/sizeof-struct/">这篇文章</a>。  既然如此，让我们先看下面几个小例子：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">double</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>上面三行sizeof的值是多少呢？这里我们假定在32位的x86系统下。<span style="color: #ff0000;">我们会得到答案：4，1，8</span>。这个没什么吧，大多数人都应该知道。那么，下面这个：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">long</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>在32位x86下，这两个是多少呢？4，8？</p>
<p><span style="color: #ff0000;">实际上，答案是4，4</span>。我们需要注意，long类型在32位系统下是32位的。那么，64位下结果又如何呢？8，8？<span style="color: #ff0000;">其实答案是4，8</span>。另一个需要注意的是，<span style="color: #ff0000;">64位下的int是32位的</span>。</p>
<p>上面只是热热身，现在，让我们看sizeof的下面几种情形：</p>
<p>1、<span style="color: #ff0000;"><strong>sizeof一个结构体。</strong></span></p>
<p>这个我就不说啥了，具体的参考<a href="../clanguage/sizeof-struct/">这篇文章</a>。至于空的结构体，下面会解释。</p>
<p><span style="color: #ff0000;"><span style="color: #000000;">2、</span><strong>sizeof数组、指针等</strong></span> 先看下面两个例子：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">char</span> a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span> b<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #ff0000;">&quot;helloworld!&quot;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span> c<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #ff0000;">&quot;helloworld!&quot;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span><span style="color: #339933;">*</span> d<span style="color: #339933;">=</span>b<span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>c<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>d<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>在32位x86系统下，以上各是多少呢？</p>
<p><span style="color: #ff0000;">答案是：100，100，12，4。</span></p>
<p>为什么不是100，12，12，12呢？  sizeof一个数组名，返回的是数组的大小，不管你数组里面放的什么数据。所以，第一个数组大小是100，第二个数组大小是100，第三个数组大小是12（别忘记"\0"）。第四个呢？第四个不是一个数组名，而是一个指针！32位下指针大小永远是4，不管你是指向一个数组还是一个int还是一个char。  好，这个问题搞清楚之后，看下面这个程序：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> func<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>m <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;helloworld!&quot;</span><span style="color: #339933;">;</span>
    func<span style="color: #009900;">&#40;</span>m<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> n<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #ff0000;">&quot;helloworld!&quot;</span><span style="color: #339933;">;</span>
    func<span style="color: #009900;">&#40;</span>n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>这个程序会打印出什么结果呢？</p>
<p><span style="color: #ff0000;">答案是：4， 4。</span> 为什么结果都是4？不是应该返回数组长度么？</p>
<p><span style="color: #ff0000;">这里出现又一个需要注意的地方：在作为参数传递的时候，数组名会退化为指针。</span>也就是说，这里的func里的参数，虽然看上去是个数组名，但实际上还是个指针。  你了解了么？下面是几个练习，自己实验下^_^</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>p <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>懒得实验？答案分别是4，1，400，4，4，4。为什么？自己想想。</p>
<p>3、<span style="color: #ff0000;"><strong>sizeof一些诡异的东西</strong></p>
<p>（enum，空类，空struct）</span> 所谓的诡异的东西，就是一些你想到的想不到的东西拿来sizeof。比如说sizeof一个enum类型是多少？一个空struct呢？一个空类呢？  这些诡异的东西在标准C中都没有作出规定，很大程度上都是编译器和系统结构相关的。  先来看一个：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">enum</span> week<span style="color: #009900;">&#123;</span>Mon<span style="color: #339933;">,</span> Tue<span style="color: #339933;">,</span> Wed<span style="color: #339933;">,</span> Thu<span style="color: #339933;">,</span> Fri<span style="color: #339933;">,</span> Sat<span style="color: #339933;">,</span> Sun<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">enum</span> week<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>这个你会得到什么样的结果呢？28？  在gcc或者vc下运行一把，<span style="color: #ff0000;">你会得到答案：4。</span></p>
<p>为什么呢？  实际上<span style="color: #ff0000;">，enum具体有多大取决于编译器的实现</span>，目前大多数的编译器都将其实现为int类型。也就是说这里的enum被当作int类型（当然，使用上不一样）。这不是一成不变的，有些编译器，如VC++允许下面这种定义：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//注意这是个cpp文件</span>
<span style="color: #000000; font-weight: bold;">enum</span> Color <span style="color: #339933;">:</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span>
<span style="color: #009900;">&#123;</span>
   red<span style="color: #339933;">,</span> green<span style="color: #339933;">,</span> blue
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// assert(sizeof(Color) == 1);</span></pre></div></div>

<p>enum先说到这里，那么<span style="color: #ff0000;">一个空的结构体是多大呢</span>？  如果你擅长C语言，你可以很快的写出下面的程序：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//this is a *.c file</span>
<span style="color: #993333;">struct</span> node<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>Node<span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> main
<span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>Node<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>很快，你可以验证出来<span style="color: #ff0000;">结果是0。</span> 没错，这很好理解。但是，如果你用的是c++呢？</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//this is a *.cpp file</span>
<span style="color: #993333;">struct</span> node<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>Node<span style="color: #339933;">;</span>
&nbsp;
class node2<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>Node2<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>Node<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>Node2<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>（不怎么会写c++的我表示压力很大）以上这个c++的例子结果是多少呢？</p>
<p><span style="color: #ff0000;">为什么会得到1，1这个结果呢？</span> 换句话说就是为什么sizeof一个空类和空结构体在c++下就是1呢？</p>
<p>这个原因要追朔到c++标准中的一句话：“<span style="color: #ff0000;">no object shall have the same address in memory as any other variable</span>”， 用中国话简单点说就是：<span style="color: #ff0000;">不同的对象之间应该有不同的地址</span>（为什么会有这样的规定？看<a href="http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a">这里</a>）。</p>
<p>既然每个对象都必须有不同的地址，让我们假设上面代码中的Node的size是0，想想会出现什么样的后果？</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">Node a<span style="color: #339933;">;</span>
Node b<span style="color: #339933;">;</span></pre></div></div>

<p>a的大小是0，b的大小是0，那么，a和b的地址是不是很可能重复了？</p>
<p>所以，<span style="color: #ff0000;">为了保证不同的对象拥有不同的地址，最简单的方法就是保证所有类型的大小都不是0</span>。</p>
<p>所以，为了保证这点，大多数c++编译器都会给空结构或类加上一个冗余的字节保证类型不为空。</p>
<p>我的解释的清楚么？如果我的表达能力不够好，看<a href="http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a">这里</a>，解释的足够详细。  当然，还有其他很多我没有想到的诡异的东西可以拿来sizeof，如果你想到了，欢迎跟我分享。至于c++中的sizeof类，基类，派生类，足够可以作为一个专门的文章了，先不再这里说，等我学会C++的再写一下相关内容（-_-"）。</p>
<p>最后，给一个稍微给力点的程序，大家看看最终得到的结果是什么(<span style="color: #ff0000;">注意这是一个c++程序</span>)：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//this is a cpp file</span>
<span style="color: #993333;">typedef</span>   <span style="color: #993333;">struct</span>   weekday_st
<span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">enum</span>   week     <span style="color: #009900;">&#123;</span>sun<span style="color: #339933;">=</span><span style="color: #0000dd;">123456789</span><span style="color: #339933;">,</span>mon<span style="color: #339933;">,</span>tue<span style="color: #339933;">,</span>wed<span style="color: #339933;">,</span>thu<span style="color: #339933;">,</span>fri<span style="color: #339933;">,</span>sat<span style="color: #339933;">,</span>a<span style="color: #339933;">,</span>b<span style="color: #339933;">,</span>c<span style="color: #339933;">,</span>d<span style="color: #339933;">,</span>e<span style="color: #339933;">,</span>f<span style="color: #339933;">,</span>g<span style="color: #339933;">,</span>h<span style="color: #339933;">,</span>i<span style="color: #339933;">,</span>j<span style="color: #339933;">,</span>k<span style="color: #339933;">,</span>l<span style="color: #339933;">,</span>m<span style="color: #339933;">,</span>n<span style="color: #339933;">,</span>o<span style="color: #339933;">,</span>p<span style="color: #339933;">,</span>q<span style="color: #339933;">,</span>r<span style="color: #339933;">,</span>s<span style="color: #339933;">,</span>t<span style="color: #339933;">,</span>u<span style="color: #339933;">,</span>v<span style="color: #339933;">,</span>w<span style="color: #339933;">,</span>x<span style="color: #339933;">,</span>y<span style="color: #339933;">,</span>z<span style="color: #339933;">,</span>aa<span style="color: #339933;">,</span>ab<span style="color: #339933;">,</span>ac<span style="color: #339933;">,</span>ad<span style="color: #339933;">,</span>ae<span style="color: #339933;">,</span>af<span style="color: #339933;">,</span>ag<span style="color: #339933;">,</span>ah<span style="color: #339933;">,</span>ai<span style="color: #339933;">,</span>aj<span style="color: #339933;">,</span>ak<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">enum</span>   day<span style="color: #009900;">&#123;</span>monring<span style="color: #339933;">,</span>   moon<span style="color: #339933;">,</span>   aftermoon<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>weekday_st<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span>   main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span>   argc<span style="color: #339933;">,</span>   <span style="color: #993333;">char</span>   <span style="color: #339933;">*</span>argv<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span> <span style="color: #ff0000;">&quot;sizeof(weekday_st)=%d<span style="color: #000099; font-weight: bold;">\n</span> &quot;</span><span style="color: #339933;">,</span>   <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>weekday_st<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span> <span style="color: #ff0000;">&quot;sizeof(weekday)=%d<span style="color: #000099; font-weight: bold;">\n</span> &quot;</span><span style="color: #339933;">,</span>   <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>weekday_st<span style="color: #339933;">::</span><span style="color: #202020;">week</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span> <span style="color: #ff0000;">&quot;sizeof(day)=%d<span style="color: #000099; font-weight: bold;">\n</span> &quot;</span><span style="color: #339933;">,</span>   <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>weekday_st<span style="color: #339933;">::</span><span style="color: #202020;">day</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span>  <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>参考书目：<a href="http://www.amazon.cn/exec/obidos/ASIN/B0012NIW9K/spongeliu-23"  target="_blank">《C专家编程》</a> <a href="http://www.amazon.cn/exec/obidos/ASIN/B003XF3GQO/spongeliu-23"  target="_blank">《C语言深度解剖:解开程序员面试笔试的秘密 》</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/sizeof/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>gdb的基本工作原理是什么？</title>
		<link>http://www.spongeliu.com/linux/howgdbwork/</link>
		<comments>http://www.spongeliu.com/linux/howgdbwork/#comments</comments>
		<pubDate>Fri, 29 Oct 2010 05:38:02 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[linux系统]]></category>
		<category><![CDATA[attach]]></category>
		<category><![CDATA[gdb基本工作原理]]></category>
		<category><![CDATA[gdb工作原理]]></category>
		<category><![CDATA[ptrace]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=240</guid>
		<description><![CDATA[还是面某M的时候，面试官问我：“用过gdb么？” 答：“用过，调了两年bug了”。“那好，给我解释下gdb是怎么工作的？或者说跟内核什么地方有关系？”。

是阿，<span style="color: #ff0000;">gdb凭什么可以调试一个程序？凭什么能够接管一个程序的运行？</span>我以前也想过这样的问题，但是后来居然忘记去查看了。我想到了我们的二进制翻译器，想到了intel的pin，Dynamo。这些都是将翻译后的代码放到codecache中去运行，然后接管整个程序的执行。gdb是不是也一样呢？

如果真是这样，为什么我记得用gdb跑一个程序，这个程序会有一个单独的进程？gdb的attach功能又是怎么实现的？

想了想，我还是没有答上来。面试就是由这么一个又一个细节的小杯具最后汇集成一个大杯具。

那么，gdb到底是凭什么接管的一个进程的执行呢？其实，很简单，<span style="color: #ff0000;">通过一个系统调用：ptrace</span>。ptrace系统调用的原型如下：]]></description>
			<content:encoded><![CDATA[<p>还是面某M的时候，面试官问我：“用过gdb么？” 答：“用过，调了两年bug了”。“那好，给我解释下gdb是怎么工作的？或者说跟内核什么地方有关系？”。</p>
<p>是阿，<span style="color: #ff0000;">gdb凭什么可以调试一个程序？凭什么能够接管一个程序的运行？</span>我以前也想过这样的问题，但是后来居然忘记去查看了。我想到了我们的二进制翻译器，想到了intel的pin，Dynamo。这些都是将翻译后的代码放到codecache中去运行，然后接管整个程序的执行。gdb是不是也一样呢？</p>
<p>如果真是这样，为什么我记得用gdb跑一个程序，这个程序会有一个单独的进程？gdb的attach功能又是怎么实现的？</p>
<p>想了想，我还是没有答上来。面试就是由这么一个又一个细节的小杯具最后汇集成一个大杯具。</p>
<p>那么，gdb到底是凭什么接管的一个进程的执行呢？其实，很简单，<span style="color: #ff0000;">通过一个系统调用：ptrace</span>。ptrace系统调用的原型如下：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;sys/ptrace.h&gt;</span>
&nbsp;
<span style="color: #993333;">long</span> ptrace<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">enum</span> __ptrace_request request<span style="color: #339933;">,</span> pid_t pid<span style="color: #339933;">,</span>
                   <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>addr<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><strong><span style="color: #ff0000;">说明：ptrace系统调用提供了一种方法来让父进程可以观察和控制其它进程的执行，检查和改变其核心映像以及寄存器。 主要用来实现断点调试和系统调用跟踪。（man手册）</span></strong></p>
<p>其实，说到这里，一切原理层面应该都比较明朗了（且先不去管内核中是怎么实现ptrace的）。gdb就是调用这个系统调用，然后通过一些参数来控制其他进程的执行的。</p>
<p>下面我们来看ptrace函数中request参数的一些主要选项：</p>
<p><span style="color: #ff0000;">PTRACE_TRACEME： </span>表示本进程将被其父进程跟踪，交付给这个进程的所有信号，即使信号是忽略处理的（除SIGKILL之外），都将使其停止，父进程将通过wait()获知这一情况。</p>
<p>这是什么意思呢？我们可以结合到gdb上来看。如果在gdb中run一个程序，首先gdb会fork一个子进程，然后该子进程调用ptrace系统调用，参数就是PTRACE_TRACEME，然后调用一个exec执行程序。基本过程是这样，细节上可能会有出入。需要注意的是，<span style="color: #ff0000;">这个选项PTRACE_TRACEME是由子进程调用的而不是父进程！</span></p>
<p><span style="color: #ff0000;"><strong>以下选项都是由父进程调用：</strong><br />
</span></p>
<p><span style="color: #ff0000;">PTRACE_ATTACH：</span>attach到一个指定的进程，使其成为当前进程跟踪的子进程，而子进程的行为等同于它进行了一次PTRACE_TRACEME操作。但是，需要注意的是，虽然当前进程成为被跟踪进程的父进程，但是子进程使用getppid()的到的仍将是其原始父进程的pid。</p>
<p>这下子gdb的attach功能也就明朗了。当你在gdb中使用attach命令来跟踪一个指定进程/线程的时候，gdb就自动成为改进程的父进程，而被跟踪的进程则使用了一次PTRACE_TRACEME，gdb也就顺理成章的接管了这个进程。</p>
<p><span style="color: #ff0000;">PTRACE_CONT：</span>继续运行之前停止的子进程。可同时向子进程交付指定的信号。</p>
<p>这个选项呢，其实就相当于gdb中的continue命令。当你使用continue命令之后，一个被gdb停止的进程就能继续执行下去，如果有信号，信号也会被交付给子进程。</p>
<p>除了以上这几个选项，ptrace还有很多其他选项，可以在linux下阅读man手册：<span style="color: #0000ff;">man ptrace</span></p>
<p>需要注意的另一点是，使用gdb调试过多线程/进程的人应该都知道，当子进程遇到一个信号的时候，gdb就会截获这个信号，并将子进程暂停下来。这是为什么呢？</p>
<p>实际上，在使用参数为PTRACE_TRACEME或PTRACE_ATTACH的ptrace系统调用建立调试关系之后，交付给目标程序的任何信号（除SIGKILL之外）都将被gdb先行截获，或在远程调试中被gdbserver截获并通知gdb。gdb因此有机会对信号进行相应处理，并根据信号的属性决定在继续目标程序运行时是否将之前截获的信号实际交付给目标程序。</p>
<p>参考资料：<a href="http://www.docin.com/p-18618736.html">gdb的基本工作原理</a><br />
<a href="http://www.amazon.cn/gp/product/0596100272/ref=as_li_tf_mfw?&#038;linkCode=wey&#038;tag=spongeliu-23" target="_blank">《gdb pocket reference》</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/linux/howgdbwork/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>C语言的那些个关键字们</title>
		<link>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/ckeyword/</link>
		<comments>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/ckeyword/#comments</comments>
		<pubDate>Thu, 28 Oct 2010 14:09:35 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[C语言]]></category>
		<category><![CDATA[语言学习]]></category>
		<category><![CDATA[const]]></category>
		<category><![CDATA[register]]></category>
		<category><![CDATA[sizeof]]></category>
		<category><![CDATA[static]]></category>
		<category><![CDATA[volatile]]></category>
		<category><![CDATA[关键字]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=236</guid>
		<description><![CDATA[最近感冒，昨天流着鼻涕去一直很想去的某M面试，居然还迟到了，一紧张，鼻涕不流了－ －#

问的问题不难，都是基础，可是自己不争气，答的不怎么样，一直自诩C语言用的很不错，可是还是在基础上被鄙视－ －！都是那些个关键字们阿～今天，让我挨个把C的关键字给详细的整一整，加深一下印象～

首先，<span style="color: #ff0000;">C语言中到底有多少个关键字呢？木有错，ANSI C规定是32个！</span> 他们分别是：auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if while static。

别看那一堆了字母了，直接看下面的分类介绍：

<strong><span style="color: #ff0000;">第一类：数据类型关键字</span></strong>
]]></description>
			<content:encoded><![CDATA[<p>最近感冒，昨天流着鼻涕去一直很想去的某M面试，居然还迟到了，一紧张，鼻涕不流了－ －#</p>
<p>问的问题不难，都是基础，可是自己不争气，答的不怎么样，一直自诩C语言用的很不错，可是还是在基础上被鄙视－ －！都是那些个关键字们阿～今天，让我挨个把C的关键字给详细的整一整，加深一下印象～</p>
<p>首先，<span style="color: #ff0000;">C语言中到底有多少个关键字呢？木有错，ANSI C规定是32个！</span> 他们分别是：auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if while static。</p>
<p>别看那一堆了字母了，直接看下面的分类介绍：</p>
<p><strong><span style="color: #ff0000;">第一类：数据类型关键字</span></strong></p>
<p>这一类别的关键字有：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">char</span>          <span style="color: #666666; font-style: italic;">//声明字符型变量或函数</span>
<span style="color: #993333;">double</span>       <span style="color: #666666; font-style: italic;">//声明双精度变量或函数</span>
<span style="color: #000000; font-weight: bold;">enum</span>         <span style="color: #666666; font-style: italic;">//声明枚举类型</span>
<span style="color: #993333;">float</span>          <span style="color: #666666; font-style: italic;">//声明浮点型变量或函数</span>
<span style="color: #993333;">int</span>            <span style="color: #666666; font-style: italic;">//声明整型变量或函数</span>
<span style="color: #993333;">long</span>          <span style="color: #666666; font-style: italic;">//声明长整型变量或函数</span>
<span style="color: #993333;">short</span>         <span style="color: #666666; font-style: italic;">//声明短整型变量或函数</span>
<span style="color: #993333;">signed</span>       <span style="color: #666666; font-style: italic;">//声明有符号类型变量或函数</span>
<span style="color: #993333;">struct</span>        <span style="color: #666666; font-style: italic;">//声明结构体变量或函数</span>
<span style="color: #993333;">union</span>         <span style="color: #666666; font-style: italic;">//声明共用体数据类型</span>
<span style="color: #993333;">unsigned</span>     <span style="color: #666666; font-style: italic;">//声明无符号类型变量或函数</span>
<span style="color: #993333;">void</span>           <span style="color: #666666; font-style: italic;">//声明函数无返回值或无参数，声明无类型指针</span></pre></div></div>

<p>这一类别的关键字无需过多的说明，基本都是我们经常用到的，但是，<span style="color: #ff0000;">仍然有些是我们需要注意的东西</span>：</p>
<ol>
<li>C 标准并未定义指针、整数型（int）、长型（long）为特定的位数目。在32位体系结构下，一般int和long都是32位长；值得注意的是，64位机器下，很多程序设计环境，“int”变量仍然是 32 位宽，“long”和指针是 64 位宽。注意，<span style="color: #ff0000;">这里说的只是一般情况下</span>！详细的解释可以看<a href="http://baike.baidu.com/view/125381.htm">这里</a>。</li>
<li>union声明的联合数据结构，里面的数据是共享内存的，可以看<a href="http://www.spongeliu.com/clanguage/%E8%84%91%E8%A2%8B%E4%B8%80%E8%BF%B7%E7%B3%8A%EF%BC%8C%E4%BA%BA%E5%B0%B1%E5%AE%B9%E6%98%93%E7%8A%AF%E4%BA%8C-union%E9%A2%98%E7%9B%AE/">我的另一篇日志</a>。</li>
<li>unsigned声明的是一个无符号数据类型，也就是说，如果unsigned int i; 需要注意变量i永远不可能等于复数，除非强制类型转换。</li>
</ol>
<p><span style="color: #ff0000;"><strong>第二类：控制语句关键字</strong></span></p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #b1b100;">for</span>         <span style="color: #666666; font-style: italic;">//循环语句</span>
<span style="color: #b1b100;">do</span>         <span style="color: #666666; font-style: italic;">//循环语句的循环体</span>
<span style="color: #b1b100;">while</span>      <span style="color: #666666; font-style: italic;">//循环语句的循环条件</span>
<span style="color: #000000; font-weight: bold;">break</span>     <span style="color: #666666; font-style: italic;">//跳出当前循环</span>
<span style="color: #b1b100;">continue</span> <span style="color: #666666; font-style: italic;">//结束当前循环，开始下一次循环</span>
<span style="color: #b1b100;">if</span>           <span style="color: #666666; font-style: italic;">//条件分支语句</span>
<span style="color: #b1b100;">else</span>       <span style="color: #666666; font-style: italic;">//条件分支语句</span>
<span style="color: #b1b100;">goto</span>      <span style="color: #666666; font-style: italic;">//无条件跳转语句</span>
<span style="color: #b1b100;">switch</span>    <span style="color: #666666; font-style: italic;">//不解释</span>
<span style="color: #b1b100;">case</span>      <span style="color: #666666; font-style: italic;">//不解释</span>
<span style="color: #b1b100;">default</span>    <span style="color: #666666; font-style: italic;">//不解释</span>
<span style="color: #b1b100;">return</span>     <span style="color: #666666; font-style: italic;">//返回语句</span></pre></div></div>

<p>这些关键字估计都快被用烂了吧？不解释！</p>
<p><strong><span style="color: #ff0000;">下面，开始做点有意义的事情，着重解释以下的关键字：</span></strong></p>
<p><span style="color: #ff0000;"><strong>第三类：存储类型关键字 </strong></span></p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">auto</span>
<span style="color: #000000; font-weight: bold;">extern</span>
<span style="color: #993333;">register</span>
<span style="color: #993333;">static</span></pre></div></div>

<p>让我们一一来看这四个关键字：</p>
<p><span style="color: #ff0000;">1、auto关键字：</span> 声明变量的生存期为自动，即将不在任何类、结构、枚举、联合和函数中定义的变量视为全局变量，而在函数中定义的变量视为局部变量。不明白？无视他好了，编译器默认的缺省情况下，所有的变量都是auto的。</p>
<p><span style="color: #ff0000;">2、extern关键字：</span> 我们都知道，一个变量或函数，可以在a.c文件中定义，而在b.c文件中使用，这个时候，b.c就需要使用extern关键字来声明这个变量和函数，目的是为了告诉编译器，这个函数在b.c之外，别让我编译不过！</p>
<p><span style="color: #ff0000;">3、register关键字：</span> 这个关键字就很少用到了，但是却十分有用。它的目的是告诉编译器尽量把这个变量放到寄存器中，这样提高存取速度，但是不是能真的放到寄存器中却不一定，毕竟寄存器的数量是有限的。在我们的二进制翻译器中，这个关键字被巧妙的用于线程切换。</p>
<p><span style="color: #ff0000;">4、static关键字：</span> 好吧，我承认我土了，我就是栽在这个关键字上的。static有两种修饰，分别如下：</p>
<p>(1)<span style="color: #ff0000;">修饰变量</span>：变量分为全局变量和静态变量，都存储在内存的静态区中。</p>
<p>首先，当static修饰全局变量的时候，<span style="color: #ff0000;">该变量的作用域仅被限定在当前文件中</span>，别的文件即使使用extern关键字也无法使用这个变量。</p>
<p>其次，当static修饰局部变量的时候，该变量在哪个函数体中定义，就只能在哪个函数体中使用。也许你会说，这不跟普通局部变量一样么？不一样！别忘了他是被存储在内存的静态区中<span style="color: #ff0000;">，所谓的静态区就是全局区</span>，用来存放全局变量和静态变量的，程序不结束，这个区是不会被释放的，所以即使定义静态局部变量的函数结束，改静态局部变量仍然存在，下次访问改函数的时候，这个变量的值仍然是上次的值！举个例子把：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">static</span> <span style="color: #993333;">int</span> i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    i<span style="color: #339933;">++;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>这个小例子的执行结果是什么呢？答案是：</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000;">1</span>
<span style="color: #000000;">2</span></pre></div></div>

<p>对的，静态局部变量只能被初始化一次，并且值会被保留，使用这个有两个好处，一个是可以计算函数被调用的次数，一个是可以减少函数构建局部变量的开销，自己体会一下把。</p>
<p>(2)<span style="color: #ff0000;">修饰函数：</span> 经常见这种形式，但没怎么用过，也就没去想。其实这个作用跟静态全局变量相似，也是限定函数的作用域为本文件。这样作的好处就是不用操心是否会跟别人编写的文件里的函数重名。（我这里栽了一下，太弱了～不甘心阿！）</p>
<p><strong><span style="color: #ff0000;">第四类：</span><span style="color: #ff0000;">其他关键字 </span></strong></p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">const</span>
<span style="color: #993333;">sizeof</span>
<span style="color: #993333;">typedef</span>
<span style="color: #993333;">volatile</span></pre></div></div>

<p>下面，也是一样，一一解释下这些关键字：</p>
<p><span style="color: #ff0000;">1、const关键字：</span> 这是一个很有意思的关键字，他修饰的变量是只读的，不能被修改；很多时候，编译器会将其优化成一个常量。const经常被用来修饰函数的参数，表示不希望这个参数值被函数体内的代码意外的改变。其实，<span style="color: #ff0000;">最有意思的是用const修饰一个指针</span>，让我们看下面这个例子：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">const</span> <span style="color: #993333;">int</span> <span style="color: #339933;">*</span>p<span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">//p可变，p指向的对象不可变</span>
<span style="color: #993333;">int</span> <span style="color: #993333;">const</span> <span style="color: #339933;">*</span>p<span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">//同上</span>
<span style="color: #993333;">int</span> <span style="color: #339933;">*</span><span style="color: #993333;">const</span> p<span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">//p不可变，p指向的对象可变</span>
<span style="color: #993333;">const</span> <span style="color: #993333;">int</span> <span style="color: #339933;">*</span><span style="color: #993333;">const</span> p<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//p和p指向的对象都不可变</span></pre></div></div>

<p>这些各表示什么呢？注释里面给出了答案！是不是很不好记？<span style="color: #ff0000;">我们只需要记得，const修饰的是*p的时候，p指向的内容不可变；const修饰的是p的时候，p就不可变！</span></p>
<p><span style="color: #ff0000;">2、sizeof关键字：</span>很多人也许会大吃一斤，我类个去，sizeof居然是关键字？（高手请无视这里，我当初就是这种表现）。不错，sizeof确实是关键字，而不是库函数！所以，如果编译时得不到一个数组的大小，那么就不能使用sizeof关键字来获取改数组的大小！</p>
<p><span style="color: #ff0000;">3、typedef关键字：</span> typedef说白了就是给一个已知的类型起一个外号。让我们考虑一个问题：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define PCHAR char*</span>
<span style="color: #993333;">typedef</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span> pchar<span style="color: #339933;">;</span></pre></div></div>

<p><span style="color: #ff0000;">这两个语句都是给char*类型起一个别名，那么哪个比较好呢</span>？ 要想知道答案，看下面：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">PCHAR p1<span style="color: #339933;">,</span> p2<span style="color: #339933;">;</span>
pchar p3<span style="color: #339933;">,</span> p4<span style="color: #339933;">;</span></pre></div></div>

<p>看代码的意思，我们是想将p1,p2,p3,p4都赋成char*类型的，但是，事实是如此么？<span style="color: #ff0000;">p2是么</span>？</p>
<p><span style="color: #ff0000;">注意，p2并没有预期成为一个char*类型，因为define会在预编译阶段展开，所以语句1就相当于 char* p1, p2；而在这条语句下，p2不是一个指针，而是一个char类型的！这个错误经常会被忽略，所以一定要注意！</span></p>
<p><span style="color: #ff0000;">4、volatile关键字：</span> 也许你见过这个关键字，但一般你都没有用过。哈哈，我用过！这个关键字表示改变量的值可能在外部被改变，编译器在用到这个变量时不能过度的优化，必须每次都重新从内存中读取这个变量的值，而不是将其优化在寄存器中。这个可以用来防止编译器优化产生的内存屏障，详细的看<a href="http://www.spongeliu.com/clanguage/memorybarrier/">这里</a>。</p>
<p>好吧，32个关键字介绍完了，我自恃很了解，也从中学了不少东西，但愿下次不要再犯这种低级的错误！没关系，一切都会好起来的！<span style="color: #ff0000;">Success is going from failure to failure without losing enthusiasm！<br />
</span></p>
<p>参考书目：<a href="http://www.amazon.cn/gp/product/B003XF3GQO/ref=as_li_tf_mfw?&#038;linkCode=wey&#038;tag=spongeliu-23" target="_blank">《C语言深度解剖:解开程序员面试笔试的秘密 》</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/ckeyword/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>内存屏障什么的</title>
		<link>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/memorybarrier/</link>
		<comments>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/memorybarrier/#comments</comments>
		<pubDate>Wed, 27 Oct 2010 16:15:32 +0000</pubDate>
		<dc:creator>sponge</dc:creator>
				<category><![CDATA[C语言]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[linux系统]]></category>
		<category><![CDATA[系统结构]]></category>
		<category><![CDATA[内存屏障]]></category>

		<guid isPermaLink="false">http://www.spongeliu.com/?p=233</guid>
		<description><![CDATA[当你看到“<span style="color: #ff0000;">内存屏障</span>”四个字的时候，你的第一反应是什么？寄存器里取出了错误的值？ifence,sfence之类的指令？还是诸如volatile之类的关键字？好吧，我第一次看到这四个字的时候，脑子里浮现出的是魔兽争霸里绿油油的铺满苔藓的<span style="color: #ff0000;">岩石屏障</span>－ －#，并且，当我搞明白内存屏障具体是什么，而且自认为对其很熟悉之后，我的第一反应依然是那几块绿油油的石头，而且很想上去A一把！

言归正传，先解释下什么是内存屏障。内存屏障是指“<span style="color: #ff0000;">由于编译器的优化和缓存的使用，导致对内存的写入操作不能及时的反应出来，也就是说当完成对内存的写入操作之后，读取出来的可能是旧的内容</span>”（摘自《独辟蹊径品内核》）。

概念就是概念，生硬的东西，懂的人能从中悟出点什么，不懂的人还是一头雾水。不要着急，我们先给内存屏障分下类，然后挨个来研究一番，等看完这篇文章，再回来读读概念，你就懂了！

<strong><span style="color: #ff0000;">内存屏障的分类：</span></strong>
<ol>
	<li>编译器引起的内存屏障</li>
	<li>缓存引起的内存屏障</li>
	<li>乱序执行引起的内存屏障</li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>当你看到“<span style="color: #ff0000;">内存屏障</span>”四个字的时候，你的第一反应是什么？寄存器里取出了错误的值？ifence,sfence之类的指令？还是诸如volatile之类的关键字？好吧，我第一次看到这四个字的时候，脑子里浮现出的是魔兽争霸里绿油油的铺满苔藓的<span style="color: #ff0000;">岩石屏障</span>－ －#，并且，当我搞明白内存屏障具体是什么，而且自认为对其很熟悉之后，我的第一反应依然是那几块绿油油的石头，而且很想上去A一把！</p>
<p>言归正传，先解释下什么是内存屏障。内存屏障是指“<span style="color: #ff0000;">由于编译器的优化和缓存的使用，导致对内存的写入操作不能及时的反应出来，也就是说当完成对内存的写入操作之后，读取出来的可能是旧的内容</span>”（摘自<a href="http://www.amazon.cn/exec/obidos/ASIN/B002JM12S6/spongeliu-23" target="_blank">《独辟蹊径品内核》</a>）。（这里概念貌似不是很准确，正确的定义：为了防止编译器和硬件的不正确优化，使得对存储器的访问顺序（其实就是变量）和书写程序时的访问顺序不一致而提出的一种解决办法。 它不是一种错误的现象，而是一种对错误现象提出的解决方发－－－－欢迎指正！！）</p>
<p>概念就是概念，生硬的东西，懂的人能从中悟出点什么，不懂的人还是一头雾水。不要着急，我们先给内存屏障分下类，然后挨个来研究一番，等看完这篇文章，再回来读读概念，你就懂了！</p>
<p><strong><span style="color: #ff0000;">内存屏障的分类：</span></strong></p>
<ol>
<li>编译器引起的内存屏障</li>
<li>缓存引起的内存屏障</li>
<li>乱序执行引起的内存屏障</li>
</ol>
<p><strong><span style="color: #ff0000;">1、编译器引起的内存屏障：</span></strong></p>
<p>我们都知道，从寄存器里面取一个数要比从内存中取快的多，所以有时候编译器为了编译出优化度更高的程序，就会把一些常用变量放到寄存器中，下次使用该变量的时候就直接从寄存器中取，而不再访问内存，这就出现了问题，当其他线程把内存中的值改变了怎么办？也许你会想，编译器怎么会那么笨，犯这种低级错误呢！是的，编译器没你想象的那么聪明！让我们看下面的代码：（代码摘自<a href="http://www.amazon.cn/exec/obidos/ASIN/B002JM12S6/spongeliu-23" target="_blank">《独辟蹊径品内核》</a>）</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> flag<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">void</span> wait<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span> flag <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span> <span style="color: #009900;">&#41;</span>
        sleep<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    ......
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> wakeup<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    flag<span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>这段代码表示一个线程在循环等待另一个线程修改flag。 Gcc等编译器在编译的时候发现，sleep()不会修改flag的值，所以，为了提高效率，它就会把某个寄存器分配给flag，于是编译后就生成了这样的伪汇编代码：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> wait<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    movl  flag<span style="color: #339933;">,</span> <span style="color: #339933;">%</span>eax<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">%</span>eax <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
        sleep<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>这时，当wakeup函数修改了flag的值，wait函数还在傻乎乎的读寄存器的值而不知道其实flag已经改变了，线程就会死循环下去。由此可见，编译器的优化带来了相反的效果！</p>
<p>但是，你又不能说是让编译器放弃这种优化，因为在很多场合下，这种优化带来的性能是十分可观的！那我们该怎么办呢？有没有什么办法可以避免这种情况？答案必须是肯定的，<span style="color: #ff0000;">我们可以使用关键字volatile来避免这种情况</span>。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">volatile</span> <span style="color: #993333;">int</span> flag <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span></pre></div></div>

<p>这样，我们就能避免编译器把某个寄存器分配给flag了。</p>
<p>好，上面所描述这些，就叫做“编译器优化引起的内存屏障”，<span style="color: #ff0000;">是不是懂了点什么？再回去看看概念？</span></p>
<p><strong><span style="color: #ff0000;">2、缓存引起的内存屏障</span></strong></p>
<p>好，既然寄存器能够引起这样的问题，那么缓存呢？我们都知道，CPU会把数据取到一个叫做cache的地方，然后下次取的时候直接访问cache，写入的时候，也先将值写入cache。</p>
<p>那么，先让我们考虑，在单核的情况下会不会出现问题呢？先想一下，单核情况下，除了CPU还会有什么会修改内存？对了，是<span style="color: #ff0000;">外部设备的DMA</span>！那么，DMA修改内存，会不会引起内存屏障的问题呢？答案是，在现在的体系结构中，不会。</p>
<p>当外部设备的DMA操作结束的时候，会有一种机制保证CPU知道他对应的缓存行已经失效了；而当CPU发动DMA操作时，在想外部设备发送启动命令前，需要把对应cache中的内容写回内存。在大多数RISC的架构中，这种机制是通过一写个特殊指令来实现的。在X86上，采用一种叫做<span style="color: #ff0000;">总线监测技术</span>的方法来实现。就是CPU和外部设备访问内存的时候都需要经过总线的仲裁，有一个专门的硬件模块用于记录cache中的内存区域，当外部设备对内存写入的时候，就通过这个硬件来判断下改内存区域是否在cache中，然后再进行相应的操作。</p>
<p>那么，什么时候才能产生cache引起的内存屏障呢？<span style="color: #ff0000;">多CPU？</span> 是的，在多CPU的系统里面，每个CPU都有自己的cache，当同一个内存区域同时存在于两个CPU的cache中时，CPU1改变了自己cache中的值，但是CPU2却仍然在自己的cache中读取那个旧值，这种结果是不是很杯具呢？因为没有访存操作，总线也是没有办法监测的，这时候怎么办？</p>
<p>对阿，怎么办呢？我们需要在CPU2读取操作之前使自己的cache失效，x86下，很多指令能做到这点，<span style="color: #ff0000;">如lock前缀的指令，cpuid, iret等</span>。内核中使用了一些函数来完成这个功能：mb(), rmb(), wmb()。用的也是以上那些指令，感兴趣可以去看下内核代码。</p>
<p><span style="color: #ff0000;"><strong>3、乱序执行引起的内存屏障：</strong></span></p>
<p>我们都知道，超标量处理器越来越流行，连龙芯都是四发射的。超标量实际上就是一个CPU拥有多条独立的流水线，一次可以发射多条指令，因此，很多允许指令的乱序执行，具体怎么个乱序方法，可以去看体系结构方面的书，这里只说内存屏障。</p>
<p>指令乱序执行了，就会出现问题，假设指令1给某个内存赋值，指令2从该内存取值用来运算。如果他们两个颠倒了，指令2先从内存中取值运算，是不是就错了？</p>
<p><span style="color: #ff0000;">对于这种情况，x86上专门提供了lfence，sfence,和mfence 指令来停止流水线：</span></p>
<p>lfence:停止相关流水线，知道lfence之前对内存进行的读取操作指令全部完成</p>
<p>sfence:停止相关流水线，知道lfence之前对内存进行的写入操作指令全部完成</p>
<p>mfence:停止相关流水线，知道lfence之前对内存进行的读写操作指令全部完成</p>
<p>好，将完这三种类型，再回去看看概念，清晰了么？如果还不明白，那就是我的表达能力太有限了，自己网上再搜搜把！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spongeliu.com/%e8%af%ad%e8%a8%80%e5%ad%a6%e4%b9%a0/clanguage/memorybarrier/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

