C复杂声明解析_第1页
C复杂声明解析_第2页
C复杂声明解析_第3页
C复杂声明解析_第4页
C复杂声明解析_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C复杂声明解析2009-12-20 23:07 258 人阅读 评论(0)收藏 举报creturningpointersfunctionreferenceparametersC语言所有复杂的指针声明, 都是由各种声明嵌套构成的。 如何解读复杂指针声明呢?右左 法则是一个既著名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的, 而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。 右左法则的英文原文是这样说的:The right-left rule: Start reading the declar

2、ation from the innermost parentheses, go right, and the n go left. When you encoun ter pare ntheses, the direct ion should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declarati on has bee n parsed.这段英文的翻译如下:右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇

3、到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符, 是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:in t (*fu nc)(i nt *p);首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func) 是一个函数,而func

4、是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。in t (*fu nc)(i nt *p, i nt (*f)(i nt*);func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有 int *和int (*)(int*)这样的形参,返回 值为int类型。再来看一看func的形参int (*f)(int*),类似前面的解释,f也是一个函数指针, 指向的函数具有int*类型的形参,返回值为int。in t (*fu nc 5)(i nt *p);func右边是一个运

5、算符,说明func是一个具有5个元素的数组,func的左边有一个*,说 明func的元素是指针,要注意这里的*不是修饰func的,而是修饰func5的,原因是运算符优先级比*高,func先跟结合,因此*修饰的是func。跳出这个括号,看右边,也是一 对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。in t (*(*fu nc)5)(i nt *p);func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳

6、出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指 向具有int*形参,返回值为int类型的函数。in t (*(*fu nc)(i nt *p)5;func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。要注意有些复杂指针声明是非法的,例如:in t fun c(void) 5;func是一个返回值为具有5个int元素的数组的函数。但 C语言的函数返回值不能为数组, 这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,

7、也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能 为数组。in t fun c5(void);func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元 素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。作为练习,下面列几个复杂指针声明给读者自己来解析,答案放在第十章里。in t (*(*fu nc)5 6)78;in t (*(*(*fu nc)(i nt *) 5)(i nt *);in t (*(*fu nc789)(i n

8、t*)5;实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性,例如对于声明:in t (*(*fu nc)(i nt *p)5;可以这样分解:typedefin t (*PARA) 5;typedef PARA (*fu nc)(i nt *);这样就容易看得多了。c言语的复杂类型声明在c言语的复杂类型声明中,我们用到3个修饰符:*、()、。含义如下:*暗示声明一个指针()暗示声明一个函数暗示声明一个数组c语言允许我们一次使用多个上面所说明的修饰符来申明一个变量,这样我们可以构造出多种多样的类别来。大家先

9、看下面的例子:int board88; II二维数组(一个8个元素的数组,元素内容还是数组)int *p; II指向指针的指针(一个指针,内容还是一个指针)int *array10; II10 个元素的数组,元素内容是指针。int (*p)10; II 一个指针,指向含有10个元素的数组。int *oof34; II3个元素的数组,存放的内容是指针,指针分别指向4个元素的数组int (*oof)34; II 一个指针指向3*4的数组。看到这里,可能有人会想,你在说些什么哦,怎么看不明白,没有关系,看完下面的3条法则,你在来看上面的内容就很清晰了。1:离名字越近的修饰符优先级越高2:,()优先级

10、比*高3 :用()括起来的表达式的优先级最高。我用这些法则来解释上面提到的例子,请看int *foo34名字:foo*、3离名字一样近,而4离的比他们远,所以*、3的优先级比4高。(法则1)而的优先级比*高(法则2)优先级关系如下:3 * 4所以int *foo34是一个3个元素的数组(第一个修饰符3),存放内容是指针(第二个修饰符 号*),指针分别指向4个元素的数组(第三个修饰符4)in t (*foo)34名字:foo优先级关系如下:(括号括起来的表达式优先级最高)* 3 4所以一个指针指向3*4的数组。下面的内容留给大家去思考:int *fun c()3;int *f3();alon g

11、zha ng是这样的:存储类别类型限定词类型 标识符这种说明会给人们一种暗示:C语言的声明是静止的、死板的,什么声明都能够以这个为基础,往上一套就 0K 了。事实真的如此吗?说句心里话,笔者也祈祷事实真的如此,这样世 界就简单多了、清静多了。但别忘了,这个世界总是让人事与愿违的。实际上,C的声明的组织形式是以嵌套为基础的,是用嵌套声明组织起来的,并非象上面所述那么死板,存储类说明符一定得放在限定词前面吗?类型说明符一定要紧贴标识符吗?不!C标准从来没有这样说过!下面来看一看C89对声明的形式是如何规定的:声明:声明说明符初始化声明符表 opt opt的意思是option,可选其中声明说明符由以

12、下三项构成:声明说明符:存储类说明符声明说明符opt类型说明符声明说明符opt类型限定符声明说明符opt在这里,一个声明说明符可以包含另一个声明说明符,这就是声明的嵌套, 这种嵌套贯穿于整个声明之中,今天我们看来一个非常简单的声明, 其实就是由多个声明嵌套组成的, 例如: static const int i=10, j=20, k=30;变量i前面就是声明说明符部分,有三个声明说明符:static con st int ,static是一个存储类说明符,它属于这种形式:static声明说明符static后面的声明说明符就是const int,const是一个类型限定符,这也是个嵌套,它是由c

13、on st声明说明符组成,最后的int是一个类型说明符,到这里已经没有嵌套了,int就是最底的一层。对于存储类说明符、类型说明符和类型限定符的排列顺序,C标准并没有规定其顺序,谁嵌套谁都可以。换言之,上面的声明可以写成 :int static const i=10, j=20, k=30; 或者 con st int static i=10, j=20, k=30;这无所谓,跟原声明是一样的。再举一个有趣的例子:const int *p; 与 int const *p;有些人会对后面一种形式感到困惑,因为他一直以来学习的都是那种死板的形式,因此他无法理解为什么那个 const可以放在int的后

14、面。实际上对于标准来说,这是再正常不过的行 为了。上面举的例子是变量的声明,函数的声明也同样道理,例如:static const int fun c(void);int main( void)int static con st (*p)(void);p=fu nc;return 0;const int static fun c(void)return 0;func的函数原型声明、函数定义跟 main内的函数指针p的声明是一样的。但是,笔者并非 鼓励大家把声明说明符写得乱七八糟,作为一个良好的风格, 应该按照已经习惯约定的方式排列说明符,但懂得其中的原理非常重要。声明static const i

15、nt i=10, j=20, k=30; 的int后面的部分就是初始化声明符表,这比较容易理解,这个符表实际上也是嵌套的:初始化声明符表:初始化声明符初始化声明符表,初始化声明符初始化声明符:声明符声明符=初值声明符是初始化声明符的主体,现在来讨论一下声明符是如何规定的:声明符:指针opt 直接声明符这里写的指针opt指的是那个指针声明符*,要注意的是,*属于声明符,而不是声明说明符 的一部分。指针opt又包含:指针:*类型限定符表opt*类型限定符表opt指针在这里有一个常见的问题,就是const int *p;与int * con st p的区别,第一个声明的const属于声明说明符,它跟

16、int 起,是用来说明*p这个声明符的,因此 con st修饰的是p所指 向的那个对象,这个对象是con st的。而第二个声明的 con st是声明符的一部分,它修饰的对象是p本身,因此 p是con st的。上面规定的第二条值得注意,这条规定产生了一种指针与con st的复杂形式,例如:con st int * con st * con st * con st p;(是不是有种想冲向厕所的冲动?)这是一种复杂的声明嵌套,如何解读这种声明?其实只要掌握了它的规律,无论它有多少个con st、多少个*都不难解读的,这个内容我将在第九章进行解释。剩下的就是直接声明符和类型限定词表的内容:直接声明符:

17、标识符(声明符)直接声明符常量表达式opt直接声明符(形式参数类型表)直接声明符(标识符表opt)类型限定符表:类型限定符类型限定符表类型限定符这一章的最后一个内容,是讨论一下typedef, typedef用来声明一个别名,typedef后面的语法,是一个声明。本来笔者以为这里不会产生什么误解的,但结果却出乎意料,产生误解的人不在少数。罪魁祸首又是那些害人的教材。在这些教材中介绍typedef的时候通常会写出如下形式:typedef int PARA;这种形式跟#define int PARA 几乎一样,如前面几章所述,这些教材的宗旨是由浅入深,但实际做出来的行为却是以偏盖全。的确,这种形式

18、在所有形式中是最简单的,但却没有对typedef进一步解释,使得不少人用#define的思维来看待typedef,把int与PARA分开来看,int是一部分,PARA是另一部分,但实际上根本就不是这么一回事。int与PARA是一个整体!就象int i:声明一样是一个整体声明,只不过 int i定义了一个变量,而typedef定义 了一个别名。这些人由于持有这种错误的观念,就会无法理解如下一些声明:typedef int a10;typedef void (*p)(void);他们会以为a10是int的别名,(*p)(void)是void的别名,但这样的别名看起来又似乎不是 合法的名字,于是陷入

19、困惑之中。实际上,上面的语句把a声明为具有10个int元素的数组的类型别名,p是一种函数指针的类型别名。虽然在功能上,typedef可以看作一个跟int PARA分离的动作,但语法上 typedef属于存储 类声明说明符,因此严格来说,typedef int PARA 整个是一个完整的声明。复杂的C声明一般被认为不是很好的编程习惯,当然也就不推荐使用。但是在读很多前辈遗留的代码时,又不得不面对这一问题。知道总比不知道好,我们还是来看看分析复杂C语言声明的规则吧,用例子分析最直观。一、“ight-left 规则看过C专家编程中的分析规则,用起来并不是很舒服,遂在网上寻找,发现还有一个著名的“ig

20、ht-left 规则。规则经翻译总结后如下:right-left 规则:0.规则中符号*读作指向的指针” 读作的数组”()读作返回的函数”1. 起始点找到声明中的标识符(Identifier),它就是你分析的起始点,读作:$(ldentifier)是”;2. 右边看你的标识符右边a) 如果发现()”,你将知道这是一个函数声明,这时你可以说 $(Identifier)是返回的函数”;b) 如果发现”,你将知道这是一个数组声明,这时你可以说$(Identifier)是的数组”;c) 继续向右,直到遇到右边声明结束或者遇到)”,继续下面。3. 左边看你的标识符左边a)如果碰到的不是我们在 0中定义的

21、符号,则直接说出它;否则按照0中定义的符号含义说出。继续向左,直到遇到左边声明结束或(”。4.重复2和3的步骤,直到声明分析完毕。二、例子详解我们从简单到复杂,循序渐进。Example 1 int *p;找到标识符:p,读作: 向右看:发现一 “”, 向左看:发现一 * ”,1)2)3)继续向左看:没有发现4)数组”。p是”;然后遇到右边声明结尾,读作:p是.的数组”;读作:p是指向的指针的数组”;0.中定义的符号,则分析结束,读作:p是指向int类型的指针的2)向右看:发现一0”,然后遇到)”读作:“unc是返回的函数”;3)向左看:发现一向右看:4)的函数”;发现一*”,然后遇到“”,读作

22、:“unc是返回指向.的指针的函数”;0”,然后右边声明结束,读作:fbnc是返回指向返回.的函数的指针5)向左看:发现一*”,读作:fbnc是返回指向返回指向.的指针的函数的指针的函数 ”;Example 2 int *(*fu nc()();1)找到标识符:func,读作:fbnc是.”;没有发现6)向左看:型的指针的函数的指针的函数.中定义的符号,则分析结束,读作:“unc是返回指向返回指向int类。三、常见不合法的声明符号组合 包括:()-cannot have an array of functions ()()-cannot have a function that returns

23、 a function ()-cannot have a function that retur ns an array复杂指针的声明2007-10-13 16:20参考了C和指针与C程序设计语言写成了下面的文档,主要是自己看着方便点:)首先看几个简单的例子int f ;/ 一个整型变量int *f; / 一个指向整型的指针不过,请看第2个声明是如何工作的:它把表达式*f声明为一个整数。根据这个事实,你肯定能推断出f是个指向整型的指针。C声明的这种解释方法可以通过下面的声明得到验证。int* f,g;它并没有声明两个指针。尽管它们之间存在空白,但星号是作 用于f的,只有f是一个指针。g只是一个

24、普通的整型变量。下面的例子,你曾见过:int f();它把f声明为一个函数,它的返回值是一个整数。旧式风格的 声明对函数的参数不提供任何信息。它只声明了f的返回类型。现在我将使用这种旧式风格,这样例子看上去简单一些,后面我将再回到完整 的原型形式。下面是一个例子:int *f();/ f是一个函数,它返回一个指向int类型的指针要想推断出它的含义,必须确定表达式*f()是如何进行求值的。首先执行的是函数调用操作符(),因为它的优先级高于间接访问操作 符。接下来的一个声明更为有趣:int (*f)();/ f是一个指向函数的指针,该函数返回一个int类型的对象确定括号的含义是分析这个声明的一个重

25、要步骤。 第2对儿括 号是函数调用操作符,但第1对儿括号只是起到聚组的作用。它迫使间接访问在函数调用之前进行,使f成为一个函数指针,它所指向的函数返回一个整型值。函数指针” 是的,程序中每个函数都位于内存中的某个位置,所以存在指向那个位置的指针是完全可能的。现在下面的这个声明应该是比较容易懂了:int *(*f)();它和前一个声明基本相同,f也是一个函数指针,它所指向的函数返回一个指向int类型的指针。必须对其进行间接访问操作才能得 到一个整型值。现在让我们把数组也考虑进去。int f;这个声明表示f是个整型数组,数组的长度暂时忽略,因为我 们现在关心的是它的类型,而不是它的长度【注】如果它

26、们的链接属性是external或者是作用函数的 参数,即使它们声明时未注明长度,也仍然是合法的。下面的声明又如何呢?int *f;这个声明又出现了两个操作符。下标的优先级更高,所以f是一个数组,它的元素类型是指向整型的指针F面的这个例子隐藏着一个圈套。不管怎样,让我们先推断它的含义。int f();f是一个函数,返回一个整型数组。这里的圈套在于这个声明是非法的函数只能返回标量值,不能返回数组。还有一个例子,颇费思量:int f();现在f似乎是一个数组,它的元素是返回值为整型的函数。但 是,这个声明也是非法的,因为数组元素必须具有相同的长度,但不同 的函数显然可能具有不同的长度。但是,下面的这

27、个声明是合法的:int (*f)();你必须找到所以的操作符,然后按照正确的次序执行它们。括 号内的表达式*f首先进行求值,所以f是一个元素为某种类型的指针 的数组。表达式()是函数调用操作符,所以f肯定是一个数组,数组 元素的类型是函数指针,它所指向的函数返回整型值。如果你弄明白了上面最后一个声明,下面这个应该是比较容易 的了:int *(*f)();它和上面那个声明的唯一区别就是多了一个间接访问操作符, 所以这个声明创建了一个指针数组,指针指向返回整型指针的函数。新式风格的例子:int (*f)(int,float);int *(*g)(int,float);前者把f声明为一个函数指针,它

28、所指向的函数接受两个参数,分别是一个整型和浮点型,并返回一个整型。后者把g声明为一个指针数组,它所指向的函数接受两个参数,分别是整型和浮点型,并返 回整型指针。【提示】如果你使用的是UNIX系统,并能访问In ternet, 你可以获得一个名叫 cdecl的程序,它可以在 C语言的声明和声明语 义之间进行转换。它可以解释一个现存的C声明:cdecl explain int (*(*f)()10;declare f as pointer to function returning pointer toarray 10 of int或者给你一个声明语义:cdecl declare x as poi

29、n ter to array 10 of poin ter to fun cti onreturni ng intint (*(*x)10)()cdecl 的源代码可以从comp.sources. unix.n ewsgroup存档文件第14卷中获得。如何理解c和c +的复杂类型声明2007-10-13 16:21如何理解c和.c +的复杂类型声明曾经碰到过让你迷惑不解、类似于int * (* (*fp1) (int) ) 10;这样的变量声明吗?本文将由易到难,一步一步教会你如何理解这种复杂的C/C+声明。我们将从每天都能碰到的较简单的声明入手,然后逐步加入const修饰符和typedef,

30、还有函数指针,最后介绍一个能够让你准确地理解任何 C/C+声明的右左法则”需要强调一下的是,复杂的C/C+声明并不是好的编程风格;我这里仅仅是教你如何去理解这些声明。注意:为了保证能够在同一行上显示代码和相关注释,本文最好在至少1024x768分辨率的显示器上阅读。让我们从一个非常简单的例子开始,如下:int n;这个应该被理解为declare n as an int (n是一个int型的变量)。接下去来看一下指针变量,如下:int *p;这个应该被理解为declare p as an int *( p是一个int *型的变量),或者说p是一个指向一个int型变量的指针。我想在这里展开讨论一下

31、:我觉得在声明一个指针(或引用)类型的变量时,最好将* (或&)写在紧靠变量之前,而不是紧跟基本类型之后。这样可以避免一些理解上的误区,比如:再来看一个指针的指针的例子:char *argv;理论上,对于指针的级数没有限制,你可以定义一个浮点类型变量的指针的指针的指针的指针,再来看如下的声明:int RollNum304;int (*p)4=RollNum;int *a5:这里,p被声明为一个指向一个4兀素(int类型)数组的指针,而q被声明为一个包含5个元素(int类型的指针)的数组。另夕卜,我们还可以在同一个声明中混合实用*和&,如下:int *p1;/ pl is a pointer t

32、o a pointer to an int. int *&p2;/ p2 is a reference to a pointerto an &*p3;/ ERROR: Pointer to a reference is illegal. int &p4;/ ERROR: Reference to a reference is illegal.注:p1是一个int类型的指针的指针;p2是一个int类型的指针 的引用;p3是一个int类型引用的指针(不合法! ); p4是一个 int类型引用的引用(不合法!)。const修饰符当你想阻止一个变量被改变,可能会用到const关键字。在

33、你给一个变量加上 con st修饰符的同时,通常需要对它进行初始 化,因为以后的任何时候你将没有机会再去改变它。例如:const int n=5;int const m=10;上述两个变量 n和m其实是同一种类型的都是con st int(整形恒量)。因为C+标准规定,const关键字放在类型或变 量名之前等价的。我个人更喜欢第一种声明方式,因为它更突 出了 const修饰符的作用。当 const与指针一起使用时,容易 让人感到迷惑。例如,我们来看一下下面的p和q的声明:const int *p;int const *q:他们当中哪一个代表 const int类型的指针(con st直接修饰i

34、nt), 哪一个代表int类型的const指针(const直接修饰指针)?实 际上,p和q都被声明为const int类型的指针。而int类型的 const指针应该这样声明:int * const r= &n;/ n has been declared as an int这里,p和q都是指向const int类型的指针,也就是说,你在 以后的程序里不能改变 *p的值。而r是一个con st指针,它在 声明的时候被初始化指向变量n (即r=&n;)之后,r的值将不再允许被改变(但*r的值可以改变)。组合上述两种const修饰的情况,我们来声明一个指向const int类型的con st指针,如下

35、:const int * const p=&n/ n has been declared as const int下面给出的一些关于const的声明,将帮助你彻底理清const的用法。不过请注意,下面的一些声明是不能被编译通过的, 因为他们需要在声明的同时进行初始化。为了简洁起见,我忽 略了初始化部分;因为加入初始化代码的话,下面每个声明都 将增加两行代码。char * p1;/ pointer topointer tocharconst char *p2;/ pointer topointer to const charchar * const * p3;/ pointer to const

36、 pointer tocharconst char * const * p4;/ pointer to const pointer to const char char * const p5;/ const pointer topointer tocharconst char * const p6;/ const pointer topointer to const charchar * const * const p7;/ const pointer to const pointer tocharconst char * const * const p8;/ const pointer to

37、 const pointer to const char注:pl是指向char类型的指针的指针;p2是指向const char类型的指针的指针;p3是指向char类型的con st指针;p4是指 向co nst char类型的con st指针;p5是指向char类型的指针的 const指针;p6是指向con st char类型的指针的 const指针; p7是指向 char 类型 const 指针的 const 指针;p8是指向 const char类型的const指针的const指针。typedef的妙用typedef给你一种方式来克服“只适合于变量而不适合于类型”的弊端。你可以如下使用 t

38、ypedef :typedef char * PCHAR;PCHAR p,q;这里的p和q都被声明为指针。(如果不使用typedef,q将被 声明为一个char变量,这跟我们的第一眼感觉不太一致!)下面有一些使用typedef的声明,并且给出了解释:typedef char * a;/ a is a pointer to a chartypedef a b();/ b is a function that returns/ a pointer to a chartypedef b *c;/ c is a pointer to a function/ that returns a pointer

39、 to a chartypedef c d();/ d is a function returning/ a pointer to a function/ that returns a pointer to a chartypedef d *e;/ e is a pointer to a function/ returning a pointer to a/ function that returns a/ pointer to a chare var10;/ var is an array of 10 pointers to/ functions returning pointers to/

40、 functions returning pointers to chars.typedef经常用在一个结构声明之前,如下。这样,当创建结构 变量的时候,允许你不使用关键字struct (在C中,创建结构变量时要求使用 struct关键字,女口 struct tagPOINT a ;而在C+ 中,struct 可以忽略,如 tagPOINT b )。typedef struct tagPOINTint x;int y;POINT;POINT p; /* Valid C code */函数指针函数指针可能是最容易引起理解上的困惑的声明。函数指针在DOS 时代写 TSR 程序时用得最多;在 Win

41、32和X-Windows时代,他们被用在需要回调函数的场合。当然,还有其它很多 地方需要用到函数指针:虚函数表,STL中的一些模板, WinNT/2K/XP系统服务等。让我们来看一个函数指针的简单例子:int (*p)(char);这里p被声明为一个函数指针,这个函数带一个char类型的参数,并且有一个int类型的返回值。另外,带有两个float类型参数、返回值是char类型的指针的指针的函数指针可以声明如 下:char * (*p)(float, float);那么,带两个char类型的const指针参数、无返回值的函数指 针又该如何声明呢?参考如下:void * (*a5)(char * const, char * const);右左法则”是一个简单的法则,但能让你准确理解所有的声明。 这个法则运用如下:从最内部的括号开始阅读声明,向右看, 然后向左看。当

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论