<?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>中文 &#187; 清林</title>
	<atom:link href="http://software.intel.com/zh-cn/blogs/author/475659/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/zh-cn/blogs</link>
	<description></description>
	<lastBuildDate>Mon, 28 May 2012 13:40:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>c++ 语法之switch语句</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/05/04/c-switch/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/05/04/c-switch/#comments</comments>
		<pubDate>Tue, 04 May 2010 02:03:16 +0000</pubDate>
		<dc:creator>清林</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[软件开发工具]]></category>
		<category><![CDATA[多核]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/05/04/c-switch/</guid>
		<description><![CDATA[switch语句在c或c++语言中是非常普通的一个语句了，而且我们也是经常用到的。而且我们使用的switch语句都是和case、default、break等语句一起使用的。 switch语句的使用可以非常的简单，也可以非常的复杂，所以你可以看到下面的一些另类的使用。 首先问一下的是：你知道switch文法是怎么定义的吗？ 学过《编译原理》的人都知道，我们要写某个语言的编译器就得定义这个语言的一个文法，这样我们才可以根据定义好的文法来写编译器，而c、c++的switch语句的文法的定义很简单，如下： switch(expression) statement 看下上面定义的文法，switch语句就是switch关键字后面接左括号，之后是表达式，之后是右括号，后面在跟语句块。 所以这个switch语句是很简单的，那么我们可以根据这个文法写下下面这样的代码： 编译输出：i=3 我们看到上面的代码在使用switch时是很简单的使用的： switch(表达式) 语句 我们看到switch表达式中的i没有匹配，所以输出的i的值还是3。 由于switch后面是个语句块，所以我们的表达式就可以写成这样： switch(i) { i=2; } 这样用{}来框取一个语句块。 我们想要i=2;这个语句，就加上default： switch(i) { default: i=2; } switch语句的文法的定义是简单的，但statement语句块的定义就不那么简单的了，我们可以非常灵活的使用这个语句块来非常灵活的使用switch语句。 我们看下switch和case使用的情况： switch(i) { default: i=2; case 1: printf("a=1\n"); break; } case后面一定是要一个整数，或是可以转换成整数的对象。但case却不一定要在语句块中的第一层，所以我们可以写成这样： 编译输出：i = 8; 由于case的实现，其实从汇编角度来说就是跳转语句，所以可以使用下面那样风格的代码： 编译输出：p = 2, pi = 3 虽然，上面的代码没有什么实际的意义，但是也可以看到另类的switch语句的用法，switch语句的用法关键就是后面的语句块，这个语句块是可以灵活的运用以达到灵活使用switch语句的目的。]]></description>
			<content:encoded><![CDATA[<p>switch语句在c或c++语言中是非常普通的一个语句了，而且我们也是经常用到的。而且我们使用的switch语句都是和case、default、break等语句一起使用的。</p>
<p>switch语句的使用可以非常的简单，也可以非常的复杂，所以你可以看到下面的一些另类的使用。</p>
<p>首先问一下的是：你知道switch文法是怎么定义的吗？</p>
<p>学过《编译原理》的人都知道，我们要写某个语言的编译器就得定义这个语言的一个文法，这样我们才可以根据定义好的文法来写编译器，而c、c++的switch语句的文法的定义很简单，如下：</p>
<p>switch(expression) statement</p>
<p>看下上面定义的文法，switch语句就是switch关键字后面接左括号，之后是表达式，之后是右括号，后面在跟语句块。</p>
<p>所以这个switch语句是很简单的，那么我们可以根据这个文法写下下面这样的代码：<br />
<img src="http://images.csdn.net/20100429/1.jpg" alt="" /></p>
<p>编译输出：i=3</p>
<p>我们看到上面的代码在使用switch时是很简单的使用的：</p>
<p>switch(表达式)</p>
<p>语句</p>
<p>我们看到switch表达式中的i没有匹配，所以输出的i的值还是3。</p>
<p>由于switch后面是个语句块，所以我们的表达式就可以写成这样：</p>
<p>switch(i)</p>
<p>{</p>
<p>i=2;</p>
<p>}</p>
<p>这样用{}来框取一个语句块。</p>
<p>我们想要i=2;这个语句，就加上default：</p>
<p>switch(i)</p>
<p>{</p>
<p>default:</p>
<p>i=2;</p>
<p>}</p>
<p>switch语句的文法的定义是简单的，但statement语句块的定义就不那么简单的了，我们可以非常灵活的使用这个语句块来非常灵活的使用switch语句。</p>
<p>我们看下switch和case使用的情况：</p>
<p>switch(i)</p>
<p>{</p>
<p>default:</p>
<p>i=2;</p>
<p>case 1:</p>
<p>printf("a=1\n");</p>
<p>break;</p>
<p>}</p>
<p>case后面一定是要一个整数，或是可以转换成整数的对象。但case却不一定要在语句块中的第一层，所以我们可以写成这样：</p>
<p><img src="http://images.csdn.net/20100429/2.jpg" alt="" /></p>
<p>编译输出：i = 8;</p>
<p>由于case的实现，其实从汇编角度来说就是跳转语句，所以可以使用下面那样风格的代码：</p>
<p><img src="http://images.csdn.net/20100429/3.jpg" alt="" /></p>
<p>编译输出：p = 2, pi = 3</p>
<p>虽然，上面的代码没有什么实际的意义，但是也可以看到另类的switch语句的用法，switch语句的用法关键就是后面的语句块，这个语句块是可以灵活的运用以达到灵活使用switch语句的目的。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/05/04/c-switch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>c++ 之类的前置声明</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/05/04/c-2/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/05/04/c-2/#comments</comments>
		<pubDate>Tue, 04 May 2010 02:02:24 +0000</pubDate>
		<dc:creator>清林</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[软件开发工具]]></category>
		<category><![CDATA[多核]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/05/04/c-2/</guid>
		<description><![CDATA[刚开始学习c++的人都会遇到这样的问题： 定义一个类 class A，这个类里面使用了类B的对象b，然后定义了一个类B，里面也包含了一个类A的对象a，就成了这样： 一编译，就出现了一个互包含的问题了，这时就有人跳出来说，这个问题的解决办法可以这样，在a.h文件中声明类B，然后使用B的指针。 然后，问题就解决了。 但是，有人知道问题是为什么就被解决的吗，也就是说，加了个前置声明为什么就解决了这样的问题。下面，让我来探讨一下这个前置声明。 类的前置声明是有许多的好处的。 我们使用前置声明的一个好处是，从上面看到，当我们在类A使用类B的前置声明时，我们修改类B时，只需要重新编译类B，而不需要重新编译a.h的（当然，在真正使用类B时，必须包含b.h）。 另外一个好处是减小类A的大小，上面的代码没有体现，那么我们来看下： 我们看上面的代码，类B的大小是12（在32位机子上）。 如果我们在类A中包含的是B的对象，那么类A的大小就是12（假设没有其它成员变量和虚函数）。如果包含的是类B的指针*b变量，那么类A的大小就是4，所以这样是可以减少类A的大小的，特别是对于在STL的容器里包含的是类的对象而不是指针的时候，这个就特别有用了。 在前置声明时，我们只能使用的就是类的指针和引用（因为引用也是居于指针的实现的）。 那么，我问你一个问题，为什么我们前置声明时，只能使用类型的指针和引用呢？ 如果你回答到：那是因为指针是固定大小，并且可以表示任意的类型，那么可以给你80分了。为什么只有80分，因为还没有完全回答到。 想要更详细的答案，我们看下下面这个类： 我们看下上面定义的这个类A，其中_b变量和get_b()函数是新增加进这个类的。 那么我问你，在增加进_b变量和get_b()成员函数后这个类发生了什么改变，思考一下再回答。 好了，我们来列举这些改变： 第一个改变当然是增加了_b变量和get_b()成员函数； 第二个改变是这个类的大小改变了，原来是4，现在是8。 第三个改变是成员_a的偏移地址改变了，原来相对于类的偏移是0，现在是4了。 上面的改变都是我们显式的、看得到的改变。还有一个隐藏的改变，想想是什么。。。 这个隐藏的改变是类A的默认构造函数和默认拷贝构造函数发生了改变。 由上面的改变可以看到，任何调用类A的成员变量或成员函数的行为都需要改变，因此，我们的a.h需要重新编译。 如果我们的b.h是这样的： 那么我们的b.h也需要重新编译。 如果是这样的： 那么我们的b.h就不需要重新编译。 像我们这样前置声明类A： class A; 是一种不完整的声明，只要类B中没有执行需要了解类A的大小或者成员的操作，则这样的不完整声明允许声明指向A的指针和引用。 而在前一个代码中的语句 A a; 是需要了解A的大小的，不然是不可能知道如果给类B分配内存大小的，因此不完整的前置声明就不行，必须要包含a.h来获得类A的大小，同时也要重新编译类B。 再回到前面的问题，使用前置声明只允许的声明是指针或引用的一个原因是只要这个声明没有执行需要了解类A的大小或者成员的操作就可以了，所以声明成指针或引用是没有执行需要了解类A的大小或者成员的操作的。]]></description>
			<content:encoded><![CDATA[<p>刚开始学习c++的人都会遇到这样的问题：</p>
<p>定义一个类 class A，这个类里面使用了类B的对象b，然后定义了一个类B，里面也包含了一个类A的对象a，就成了这样：</p>
<p><img src="http://images.csdn.net/20100429/402.jpg" alt="" /></p>
<p>一编译，就出现了一个互包含的问题了，这时就有人跳出来说，这个问题的解决办法可以这样，在a.h文件中声明类B，然后使用B的指针。<br />
<img src="http://images.csdn.net/20100429/5.jpg" alt="" /></p>
<p>然后，问题就解决了。</p>
<p>但是，有人知道问题是为什么就被解决的吗，也就是说，加了个前置声明为什么就解决了这样的问题。下面，让我来探讨一下这个前置声明。</p>
<p>类的前置声明是有许多的好处的。</p>
<p>我们使用前置声明的一个好处是，从上面看到，当我们在类A使用类B的前置声明时，我们修改类B时，只需要重新编译类B，而不需要重新编译a.h的（当然，在真正使用类B时，必须包含b.h）。</p>
<p>另外一个好处是减小类A的大小，上面的代码没有体现，那么我们来看下：</p>
<p><img src="http://images.csdn.net/20100429/6.jpg" alt="" /></p>
<p>我们看上面的代码，类B的大小是12（在32位机子上）。</p>
<p>如果我们在类A中包含的是B的对象，那么类A的大小就是12（假设没有其它成员变量和虚函数）。如果包含的是类B的指针*b变量，那么类A的大小就是4，所以这样是可以减少类A的大小的，特别是对于在STL的容器里包含的是类的对象而不是指针的时候，这个就特别有用了。</p>
<p>在前置声明时，我们只能使用的就是类的指针和引用（因为引用也是居于指针的实现的）。</p>
<p>那么，我问你一个问题，为什么我们前置声明时，只能使用类型的指针和引用呢？</p>
<p>如果你回答到：那是因为指针是固定大小，并且可以表示任意的类型，那么可以给你80分了。为什么只有80分，因为还没有完全回答到。</p>
<p>想要更详细的答案，我们看下下面这个类：</p>
<p><img src="http://images.csdn.net/20100429/701.jpg" alt="" /><br />
我们看下上面定义的这个类A，其中_b变量和get_b()函数是新增加进这个类的。</p>
<p>那么我问你，在增加进_b变量和get_b()成员函数后这个类发生了什么改变，思考一下再回答。</p>
<p>好了，我们来列举这些改变：</p>
<p>第一个改变当然是增加了_b变量和get_b()成员函数；</p>
<p>第二个改变是这个类的大小改变了，原来是4，现在是8。</p>
<p>第三个改变是成员_a的偏移地址改变了，原来相对于类的偏移是0，现在是4了。</p>
<p>上面的改变都是我们显式的、看得到的改变。还有一个隐藏的改变，想想是什么。。。</p>
<p>这个隐藏的改变是类A的默认构造函数和默认拷贝构造函数发生了改变。</p>
<p>由上面的改变可以看到，任何调用类A的成员变量或成员函数的行为都需要改变，因此，我们的a.h需要重新编译。</p>
<p>如果我们的b.h是这样的：</p>
<p><img src="http://images.csdn.net/20100429/8.jpg" alt="" /></p>
<p>那么我们的b.h也需要重新编译。</p>
<p>如果是这样的：<br />
<img src="http://images.csdn.net/20100429/9.jpg" alt="" /></p>
<p>那么我们的b.h就不需要重新编译。</p>
<p>像我们这样前置声明类A：</p>
<p>class A;</p>
<p>是一种不完整的声明，只要类B中没有执行需要了解类A的大小或者成员的操作，则这样的不完整声明允许声明指向A的指针和引用。</p>
<p>而在前一个代码中的语句</p>
<p>A a;</p>
<p>是需要了解A的大小的，不然是不可能知道如果给类B分配内存大小的，因此不完整的前置声明就不行，必须要包含a.h来获得类A的大小，同时也要重新编译类B。</p>
<p>再回到前面的问题，使用前置声明只允许的声明是指针或引用的一个原因是只要这个声明没有执行需要了解类A的大小或者成员的操作就可以了，所以声明成指针或引用是没有执行需要了解类A的大小或者成员的操作的。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/05/04/c-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

