RECORDING MY FANTASY

Monday, May 21, 2007

你应当如何学习C++(以及编程)(rev#1) By 刘未鹏

你应当如何学习C++(以及编程)(rev#1)

By 刘未鹏(pongba)

C++的罗浮宫(http://blog.csdn.net/pongba)

Javascript是世界上最受误解的语言,其实C++何尝不是。坊间流传的错误的C++学习方法一抓就是一大把。我自己在学习C++的过程中也走了许多弯路,浪费了不少时间。

为什么会存在这么多错误认识?原因主要有三个,一是C++语言的细节太多。二是一些著名的C++书籍总在(不管有意还是无意)暗示语言细节的重要性和有趣。三是现代C++的开发哲学必须用到一些犄角旮旯的语言细节(但注意,是库设计,不是日常编程)。这些共同塑造了C++社群的整体心态和哲学。

单是第一条还未必能够成气候,其它语言的细节也不少(尽管比起C++起来还是小巫见大巫),就拿javascript来说,作用域规则,名字查找,closurefor/in,这些都是细节,而且其中还有违反直觉的。但许多动态语言的程序员的理念我猜大约是学到哪用到哪罢。但C++就不一样了,学C++之人有一种类似于被暗示的潜在心态,就是一定要先把语言核心基本上吃透了才能下手写出漂亮的程序。这首先就错了。这个意识形成的原因在第二点,C++书籍。市面上的C++书籍不计其数,但有一个共同的缺点,就是讲语言细节的书太多——《C++ gotchas》,《Effective C++》,《More Effective C++》,但无可厚非的是,C++是这样一门语言:要拿它满足现代编程理念的需求,尤其是C++库开发的需求,还必须得关注语言细节,乃至于在C++中利用语言细节已经成了一门学问。比如C++模板在设计之初根本没有想到模板元编程这回事,更没想到C++模板系统是图灵完备的,这也就导致了《Modern C++ Design》和《C++ Template Metaprogramming》的惊世骇俗。这些技术的出现为什么惊世骇俗,打个比方,就好比是一块大家都认为已经熟悉无比,再无秘密可言的土地上,突然某天有人挖到原来地下还蕴藏着最丰富的石油。在这之前的C++虽然也有一些细节,但也还算容易掌握,那可是C++程序员们的happy old times,因为C++的一切都一览无余,everything is figured out。然而《Modern C++ Design》的出世告诉人们,“瞧,还有多少细节你们没有掌握啊。”于是C++程序员们久违的激情被重燃起来,奋不顾身的踏入细节的沼泽中。尤其是,模板编程将C++的细节进一步挖掘到了极致——我们干嘛关心涉及类对象的隐式转换的优先级高低?看看boost::is_base_of就可以知道有多诡异了。但最大的问题还在于,对于这些细节的关注还真有它合适的理由:我们要开发现代模板库,要开发active library,就必须动用模板编程技术,要动用模板编程技术,就必须利用语言的犄角旮旯,enable_iftype_traits,甚至连早就古井无波的C宏也在乱世中重生,看看boost::preprocessor有多诡异就知道了,连C宏的图灵完备性(预编译期的)都被挖掘出来了。为什么要做这些?好玩?标榜?都不是,开发库的实际需求。但这也正是最大的悲哀了。在boost里面因实际需求而动用语言细节最终居然能神奇的完成任务的最好教材就是boost::foreach,这个小设施对语言细节的发掘达到了惊天地泣鬼神的地步,不信你先试着自己去看看它的源代码,再看看作者介绍它的文章吧。而boost::typeof也不甘其后——C++语言里面有太多被“发现”而不是被“发明”的技术。难道最初无意设置这些语言规则的家伙们都是oracles

因为没有variadic templates,人们用宏加上缺省模板参数来实现类似效果。因为没有concepts,人们用模板加上析构函数的细节来完成类似工作。因为没有typeof,人们用模板元编程和宏加上无尽的细节来实现目标… C++开发者们的DIY精神不可谓不强。

然而,如果仅仅是因为要开发优秀的库,那么涉及这些细节都还是情有可原的,至少在C++09出现并且编译器厂商跟上之前,这些都还能说是不得已而为之。但我们广大的C++程序员呢?大众是容易被误导的,我也曾经是。以为掌握了更多的语言细节就更牛,但实际却是那些语言细节十有八九是平时编程用都用不到的。C++中众多的细节虽然在库设计者手里面有其用武之地,但普通程序员则根本无需过多关注,尤其是没有实际动机的关注一般性编码实践准则,以及基本的编程能力和基本功,乃至基本的程序设计理论以及算法设计。才是真正需要花时间掌握的东西。

学习最佳编码实践比学习C++更重要。看优秀的代码也比埋头用差劲的编码方式写垃圾代码要有效。直接、清晰、明了、KISS地表达意图比玩编码花招要重要

避免去过问任何语言细节,除非必要。这个必要是指在实际编程当中遇到问题,这样就算需要过问细节,也是最省事的,懒惰者原则嘛。一个掌握了基本的编程理念并有较强学习能力的程序员在用一门陌生的语言编程时就算拿着那本语言的圣经从索引翻起也可以编出合格的程序来。十年学会编程不是指对每门语言都得十年,那一辈子才能学几门语言哪,如果按字母顺序学的话一辈子都别指望学到Ruby;十年学习编程更不是指先把语言特性从粗到细全都吃透才敢下手编程,在实践中提高才是最重要的。

至于这种抠语言细节的哲学为何能在社群里面呈野火燎原之势,就是一个心理学的问题了。想像人们在论坛上讨论问题时,一个对语言把握很细致的人肯定能够得到更多的佩服,而由于论坛上的问题大多是小问题,所以解决实际问题的真正能力并不能得到显现,也就是说,知识型的人能够得到更多佩服,后者便成为动力和仿效的砝码。然而真正的编程能力是与语言细节没关系的,熟练运用一门语言能够帮你最佳表达你的意图,但熟练运用一门语言绝不意味着要把它的边边角角全都记住懂得一些常识,有了编程的基本直觉,遇到一些细节错误的时候再去查书,是最节省时间的办法

C++的书,Bjarne的圣经《The C++ Programming Language》是高屋建瓴的。《大规模C++程序设计》是挺务实的。《Accelerated C++》是最佳入门的。《C++ Templates》是仅作参考的。《C++ Template Metaprogramming》是精力过剩者可以玩一玩的,普通程序员碰都别碰的。《ISO.IEC C++ Standard 14882》不是拿来读的。Bjarne最近在做C++的教育,新书是绝对可以期待的。

P.S. 关于如何学习编程,g9blog上有许多精彩的文章:这里这里这里这里 实际上,我建议你去把g9老大的blog翻个底朝天 :P

P.S. 书单?我是遑于给出一个类似《C++初学者必读》这种书单的。C++的书不计其数,被公认的好书也不胜枚举。只不过有些书容易给初学者造成一种错觉,就是“学习C++就应该是这个样子的”。比如有朋友提到的《高质量C/C++编程》,这本书有价值,但不适合初学者,初学者读这样的书容易一叶障目不见泰山。实际上,正确的态度是,细节是必要的。但细节是次要的。其实学习编程我觉得应该最先学习如何用伪码表达思想呢,君不见《Introduction to Algorithm》里面的代码?《TAOCP》中的代码?哦,对了它们是自己建立的语言,但这种仅教学目的的语言的目的就是为了避免让写程序的人一开始就忘了写程序是为了完成功能以为写程序就是和语言细节作斗争了Bjarne说程序的正确性最重要,boost的编码标准里面也将正确性列在性能前面。

此外,一旦建立了正确的学习编程的理念,其实什么书(只要不是太垃圾的)都有些用处。都当成参考书,用的时候从目录或索引翻,基本就对了

再再P.S. myan老大和g9老大都给出了许多精彩的见解。我不得不再加上一个P.S。具体我就不摘录了,如果你读到这里,请务必往下看他们的评论。转载者别忘了转载他们的评论:-)

许多朋友都问我同一个问题,到底要不要学习C++。其实这个问题问得很没有意义。“学C++”和“不学C++”这个二分法是没意义的,为什么?因为这个问题很表面,甚至很浮躁。重要的不是你掌握的语言,而是你掌握的能力,借用myan老大的话,“重要的是这个磨练过程,而不是结果,要的是你粗壮的腿,而不是你身上背的那袋盐巴。”。此外学习C++的意义其实真的是醉翁之意不在酒,像C/C++这种系统级语言,在学习的过程中必须要涉及到一些底层知识,如内存管理、编译连接系统、汇编语言、硬件体系结构等等等等知识(注意,这不包括过分犄角旮旯的语言枝节)。这些东西也就是所谓的内功了(其实最最重要的内功还是长期学习所磨练出来的自学能力)。对此大嘴Joel在《Joel On Software》里面提到的漏洞抽象定律阐述得就非常漂亮。

所以,答案是,让你成为高手的并不是你掌握什么语言,精通C++未必就能让你成为高手,不精通C++也未必就能让你成为低手。我想大家都不会怀疑g9老大如果要抄起C++做一个项目的话会比大多数自认熟练C++的人要做得漂亮。所以关键的不是语言这个表层的东西,而是底下的本质矛盾。当然,不是说那就什么语言都不要学了,按照一种曹操的逻辑,“天下语言,唯imperativedeclarative耳”。C++是前者里面最复杂的一种,支持最广泛的编程范式。借用当初数学系入学大会上一个老师的话,“你数学都学了,还有什么不能学的呢?”。学语言是一个途径,如果你把它用来磨练自己,可以。如果你把它用来作为学习系统底层知识的钥匙,可以。如果你把它用来作为学习如何编写优秀的代码,如何组织大型的程序,如何进行抽象设计,可以。如果掉书袋,光啃细节,我认为不可以(除非你必须要用到细节,像boost库的coder们)。

然后再借用一下g9老大的《银弹和我们的职业》中的话:

银弹和我们的职业发展有什么相干?很简单:我们得把时间用于学习解决本质困难。新技术给高手带来方便。菜鸟们却不用指望被新技术拯救。沿用以前的比喻 一流的摄影师不会因为相机的更新换代而丢掉饭碗,反而可能借助先进技术留下传世佳作。因为摄影的本质困难,还是摄影师的艺术感觉。热门技术也就等于相机。 不停追新,学习这个框架,那个软件,好比成天钻研不同相机的说明书。而热门技术后的来龙去脉,才好比摄影技术。为什么推出这个框架?它解决了什么其它框架 不能解决的问题?它在哪里适用?它在哪里不适用?它用了什么新的设计?它改进了哪些旧的设计?Why is forever. 朋友聊天时提到Steve McConnell的《Professional Software Development》里面引了一个调查,说软件开发技术的半衰期20年。也就是说20年后我们现在知识里一半的东西过时。相当不坏。朋友打趣道: 该说20年后IT界一半的技术过时,我们学的过时技术远远超过这个比例。具体到某人,很可能5年他就废了。话虽悲观,但可见选择学习内容的重要性。学习 本质技艺(技术迟早过时,技艺却常用长新)还有一好处,就是不用看着自己心爱的技术受到挑战的时候干嚎。C/C++过时就过时了呗,只要有其它的系统编程 语言。Java倒了就倒了呗,未必我不能用.NETRuby昙花一现又如何。如果用得不爽,换到其它动态语言就是了。J2EE被废了又怎样?未必我们就 做不出分布系统了?这里还举了更多的例子

一句话,只有人是真正的银弹。职业发展的目标,就是把自己变成银弹。那时候,你就不再是人,而是人弹。

最后就以我在Bjarne的众多访谈当中摘录的一些关于如何学习C++(以及编程)的看法结束吧(没空逐段翻译了,只将其中我觉得最重要的几段译了一下,当然,其它也很重要,这些段落是在Bjarne的所有采访稿中摘抄出来的,所以强烈建议都过目一下):

I suspect that people think too little about what they want to build, too little about what would make it correct, and too much about "efficiency" and following fashions of programming style. The key questions are always: "what do I want to do?" and "how do I know that I have done if?". Strategies for testing enters into my concerns from well before I write the firat line of code, and that despite my view that you have to write code very early - rather than wait until a design is complete.

译:我感觉人们过多关注了所谓“效率”以及跟随编程风格的潮流,却严重忽视了本不该被忽视的问题,如“我究竟想要构建什么样的系统”、“怎样才能使它正确”。最关键的问题永远是“我究竟想要做什么?”和“如何才能知道我的系统是否已经完成了呢?”就拿我来说吧,我会在编写第一行代码之前就考虑测试方案,而且这还是在我关于应当早于设计完成之前就进行编码的观点的前提之下。

Obviously, C++ is very complex. Obviously, people get lost. However, most peple get lost when they get diverted into becoming language lawyers rather than getting lost when they have a clear idea of what they want to express and simply look at C++ language features to see how to express it. Once you know data absreaction, class hierarchies (object-oriented programming), and parameterization with types (generic programming) in a fairly general way, the C++ language features fall in place.

译:诚然,C++非常复杂。诚然,人们迷失其中了。然而问题是,大多数人不是因为首先对自己想要表达什么有了清晰的认识只不过在去C++语言中搜寻合适的语言特性时迷失的,相反,大多数人是在不觉成为语言律师的路上迷失在细节的丛林中的。事实是只需对数据抽象、类体系结构(OOP)以及参数化类型(GP)有一个相当一般层面的了解,C++纷繁的语言特性也就清晰起来了。

Well, I don't think I made such a trade-off. I want elegant and efficient code. Sometimes I get it. These dichotomies (between efficiency versus correctness, efficiency versus programmer time, efficiency versus high-level, et cetera.) are bogus.

I think the real problem is that "we" (that is, we software developers) are in a permanent state of emergency, grasping at straws to get our work done. We perform many minor miracles through trial and error, excessive use of brute force, and lots and lots of testing, but--so often--it's not enough.

Software developers have become adept at the difficult art of building reasonably reliable systems out of unreliable parts. The snag is that often we do not know exactly how we did it: a system just "sort of evolved" into something minimally acceptable. Personally, I prefer to know when a system will work, and why it will.

There are more useful systems developed in languages deemed awful than in languages praised for being beautiful--many more. The purpose of a programming language is to help build good systems, where "good" can be defined in many ways. My brief definition is, correct, maintainable, and adequately fast. Aesthetics matter, but first and foremost a language must be useful; it must allow real-world programmers to express real-world ideas succinctly and affordably.

I'm sure that for every programmer that dislikes C++, there is one who likes it. However, a friend of mine went to a conference where the keynote speaker asked the audience to indicate by show of hands, one, how many people disliked C++, and two, how many people had written a C++ program. There were twice as many people in the first group than the second. Expressing dislike of something you don't know is usually known as prejudice. Also, complainers are always louder and more certain than proponents--reasonable people acknowledge flaws. I think I know more about the problems with C++ than just about anyone, but I also know how to avoid them and how to use C++'s strengths.

In any case, I don't think it is true that the programming languages are so difficult to learn. For example, every first-year university biology textbook contains more details and deeper theory than even an expert-level programming-language book. Most applications involve standards, operating systems, libraries, and tools that far exceed modern programming languages in complexity. What is difficult is the appreciation of the underlying techniques and their application to real-world problems. Obviously, most current languages have many parts that are unnecessarily complex, but the degree of those complexities compared to some ideal minimum is often exaggerated.

We need relatively complex language to deal with absolutely complex problems. I note that English is arguably the largest and most complex language in the world (measured in number of words and idioms), but also one of the most successful.

C++ provides a nice, extended case study in the evolutionary approach. C compatibility has been far harder to maintain than I or anyone else expected. Part of the reason is that C has kept evolving, partially guided by people who insist that C++ compatibility is neither necessary nor good for C. Another reason-- probably even more important--is that organizations prefer interfaces that are in the C/C++ subset so that they can support both languages with a single effort. This leads to a constant pressure on users not to use the most powerful C++ features and to myths about why they should be used "carefully," "infrequently," or "by experts only." That, combined with backwards-looking teaching of C++, has led to many failures to reap the potential benefits of C++ as a high-level language with powerful abstraction mechanisms.

The question is how deeply integrated into the application those system dependencies are. I prefer the application to be designed conceptually in isolation from the underlying system, with an explicitly defined interface to "the outer world," and then integrated through a thin layer of interface code.

Had I had a chance to name the style of programming I like best, it would have been "class-oriented programming", but then I'm not particularly good at finding snappy names. The school of thought that I belong to - rooted in Simula and related design philosophies - emphasizes the role of compile-time checking and flexible (static) type systems. Reasoning about the behavior of a program has to be rooted in the (static) structure of the source code. The focus should be on guarantees, invariant, etc. which are closely tied to that static structure. This is the only way I know to effectively deal with correctness. Testing is essential but cannot be systematic and complete without a good internal program structure - simple-minded blackbox testing of any significant system is infeasible because of the exponential explosion of states.

So, I recommend people to think in terms of class invariants, exception handling guarantees, highly structured resource management, etc. I should add that I intensely dislike debugging (as ah hoc and unsystematic) and strongly prefer reasoning about source code and systematic testing.

Pros: flexibility, generality, performance, portability, good tool support, available on more platforms than any competitor except C, access to hardware and system resources, good availability of programmers and designers. Cons: complexity, sub-optimal use caused by poor teaching and myths.

Monday, May 14, 2007

ARM GNU常用汇编语言介绍 zz

ARM汇编语言源程序语句,一般由指令,伪操作,宏指令和伪指令作成.

ARM汇编语言的设计基础是汇编伪指令,汇编伪操作和宏指令.

伪操作,是ARM汇编语言程序里的一些特殊的指令助记符,其作用主要是为完成汇编程序做各种准备工作,在源程序运行汇编程序处理,而不是在计算机运行期间有机器执行.也就是说,这些伪操作只是汇编过程中起作用,一旦汇编结束,伪操作的使命也就随之消失.

宏指令,是一段独立的程序代码,可以插在程序中,它通过伪操作来定义,宏在被使用之前必须提前定义好,宏之间可以互相调用,也可自己递归调用.通过直接书 写宏名来使用宏.并本具宏指令的格式输入输出参数.宏定义本身不产生代码,只是在调用它时把宏体插入到原程序中.宏与C语言中的子函数形参和实参的调用相 似,调用宏时通过实际的指令来 代替宏体实现相关的一段代码,但宏的调用与子程序的调用有本质的区别,既宏并不会节省程序的空间,其优点是简化程序代码,提高程序的可读性以及宏内容可以 同步修改.

伪操作,宏指令一般与编译程序有关,因此ARM汇编语言的伪操作,宏指令在不同的编译环境下有不同的编写形式和规则.

伪指令也是ARM汇编语言程序里的特殊助记符,也不在处理器运行期间由机器执行,他们在汇编时将被合适的机器指令代替成ARM或Thumb指令,从而实现真正的指令操作.

4.1 ARM GNU常用汇编伪指令介绍
1. abort
.abort: 停止汇编

.align absexpr1,absexpr2:
以某种对齐方式,在未使用的存储区域填充值. 第一个值表示对齐方式,4, 8,16或32. 第二个表达式值表示填充的值.

2. if...else...endif
.if
.else
.endif: 支持条件预编译

3. include
.include "file": 包含指定的头文件, 可以把一个汇编常量定义放在头文件中.
4. comm
.comm symbol, length:在bss段申请一段命名空间,该段空间的名称叫symbol, 长度为length. Ld连接器在连接会
为它留出空间.

5. data
.data subsection: 说明接下来的定义归属于subsection数据段.

6. equ
.equ symbol, expression: 把某一个符号(symbol)定义成某一个值(expression).该指令并不分配空间.

7. global
.global symbol: 定义一个全局符号, 通常是为ld使用.

8. ascii
.ascii "string": 定义一个字符串并为之分配空间.

9. byte
.byte expressions: 定义一个字节, 并为之分配空间.

10. short
.short expressions: 定义一个短整型, 并为之分配空间.

11. int
.int expressions: 定义一个整型,并为之分配空间.

12 long
.long expressions: 定义一个长整型, 并为之分配空间.

13 word
.word expressions: 定义一个字,并为之分配空间, 4bytes.

14. macro/endm
.macro: 定义一段宏代码, .macro表示代码的开始, .endm表示代码的结束.

15. req
name .req register name: 为寄存器定义一个别名.

16. code
.code [16|32]: 指定指令代码产生的长度, 16表示Thumb指令, 32表示ARM指令.

17. ltorg
.ltorg: 表示当前往下的定义在归于当前段,并为之分配空间.

4.2 ARM GNU专有符号
1. @
表示注释从当前位置到行尾的字符.

2. #
注释掉一整行.

3. ;
新行分隔符.

4.3 操作码

1. NOP
nop
空操作, 相当于MOV r0, r0





2. LDR
ldr , =
相当于PC寄存器或其它寄存器的长转移.

3.ADR
adr

Tuesday, May 08, 2007

计算n的阶乘n!末尾所含有“0”的个数

声明:来自chinaunix论坛帖子http://www.chinaunix.net/jh/23/926848.html

问题描述

给定参数n(n为正整数),请计算n的阶乘n!末尾所含有0的个数。

例如,5!=120,其末尾所含有的0的个数为1;10!= 3628800,其末尾所含有的0的个数为2;20!= 2432902008176640000,其末尾所含有的0的个数为4。

计算公式

令f(x)表示正整数x末尾所含有的0的个数,则有

当n <>= 5时,f(n!) = k + f(k!), 其中 k = n / 5(取整)。

问题分析

显然,对于阶乘这个大数,我们不可能将其结果计算出来,再统计其末尾所含有的0的个数。所以必须从其数字特征进行分析。下面我们从因式分解的角度切入分析。

我们先考虑一般的情形。对于任意一个正整数,若对其进行因式分解,那么其末尾的0必可以分解为2*5。在这里,每一个0必然和一个因子5相对应。但请注意,一个数的因式分解中因子5不一定对应着一个0,因为还需要一个因子2,才能实现其一一对应。

我们再回到原先的问题。这里先给出一个结论:

结论1: 对于n的阶乘n!,其因式分解中,如果存在一个因子5,那么它必然对应着n!末尾的一个0

下面对这个结论进行证明:

(1)当n 在 0, 5 之间时,f(n!) = 0;

(2)当n >= 5时,令n!= [5k * 5(k-1) * ... * 10 * 5] * a,其中 n = 5k + r (0 <= r <= 4),a是一个不含因子5的整数。

对于序列5k, 5(k-1), ..., 10, 5中每一个数5i(1 <= i <= k),都含有因子5,并且在区间(5(i-1),5i)(1 <= i <= k)内存在偶数,也就是说,a中存在一个因子2与5i相对应。即,这里的k个因子5与n!末尾的k个0一一对应。

我们进一步把n!表示为:n!= 5^k * k! * a(公式1),其中5^k表示5的k次方。很容易利用(1)和迭代法,得出结论1。

上面证明了n的阶乘n!末尾的0与n!的因式分解中的因子5是一一对应的。也就是说,计算n的阶乘n!末尾的0的个数,可以转换为计算其因式分解中5的个数。

令f(x)表示正整数x末尾所含有的0的个数, g(x)表示正整数x的因式分解中因子5的个数,则利用上面的的结论1和公式1有:

f(n!) = g(n!) = g(5^k * k! * a) = k + g(k!) = k + f(k!)

所以,最终的计算公式为:

当n < size="2">当n >= 5时,f(n!) = k + f(k!), 其中 k = n / 5(取整)。

============

这是帖子作者给出的笔记,后面有人回帖提到在柯召,孙琦的《数论讲义》上册的数论函数部分中就有。

Pot_p(n!) = [n/p] + Pot_p([n/p]!)

递归使用这个公式就可以得到 Pot_p(n!) 的表达式。

Thursday, May 03, 2007

恭王府花园半日游

好久之前就听好多同学说“恭王府”不错,很值得去一次,可惜一直没有时间去。转眼5.1到了,7天的假期要好好珍惜。因为,假期过后,就得抓紧时间作毕设了,7月份要中期检查,还要在这之前完成自己的小论文....。赶紧趁5.1难得的假期出去玩一趟吧。^_^
昨天是5月2号,天上飘着些白云,偶尔会遮住太阳。虽然夏天来了,天气越来越热,但昨天的温度还可以,并不是像今天这样热的变态。
我和3个同学一起去的,考虑到恭王府离北航并不是很远(810大概20多分钟的路程),而且起床比较晚,起来的时候都10点了,干脆我们就先去食堂吃了午饭,从超市买了几瓶水就出发了。
恭王府和什刹海离的很近,它们在北海北门的地方分道扬镳,恭王府在西边,什刹海在东边。可能是中午好多旅游团都休息的原因吧,中午到恭王府的路上人还好,不是非常多。路边的小店到处在兜售《和珅密传》和仿制的福字,不过看上去这门生意不是很好做。
今天在维基百科和google上查了一下恭王府,才知道现在开放的只是恭王府很小的一部分-恭王府花园。虽然恭王府花园很小,但是绝大多数的精华就在这个花园里面了。去历史氛围很重的地方游玩,最重要的是找寻一个讲解比较精彩和细心的导游--我们去的时候就跟对了导游,除去 她对恭王府纪念品的推销有一些过分热情之外,她的表现真是非常的完美。哈哈
据说,和珅对府院的设计极为细心,恭王府内的建筑布局、雕刻都蕴含着很深的意味。在古代,蝙蝠与“福”谐音,是吉祥的象征;在恭王府内到处都可以看到“福”的踪迹,进西洋门、见独乐峰,紧接着就是一个倒挂蝙蝠形状的小湖,边上的回廊上刻的都是蝙蝠形状的小装饰。还有窗户上的暗蝠,不一而足。据导游介绍一共有999个蝙蝠,再加上恭王府一绝的福字碑上由康熙亲自书写的福字,加在一起就是“万福”。
顺着导游的指引,接着来到了流杯亭。
东南角有一小景,名曰“流杯亭”,据说在清代等级森严的制约下,北京只建了六座类似的亭子,此亭为六中之最小的一座。亭上四周有忠孝节义典故的彩绘,亭中 地面有弯曲凹槽,正看呈“寿”字,垂直呈“水”字,正北入水口为“主位”,当年和珅经常在这里喝酒吟诗,地面凹槽通水后取“曲水流觞”之意境。流水的水波 推动酒杯缓缓前行,杯止行酒令,好一幅风雅文人行酒做乐之景致。
导游介绍说 谁做到水流出的地方就有好福气,可惜最开始过去的时候人太多了挤不过去,只好在逛完一遍之后在去重温一下。^-^
她还给我们介绍 康熙 写这个福字的典故。这些在网上都可以找到,就不说啦。
接着,我们进了垂花门,穿过垂花门内的牡丹院,院中有紫藤萝架。过了一会就到了花园的后门了,导游把人都集中到那里,说,大家来的时间很好,还能够摸到福字碑上的福字。因为之前拓字、游人太多,导致福字碑损害严重,现在只能用一层玻璃给保护起来了;随着可以预见的人流还会持续的增加,国家正考虑过一段后要封洞--果真那样的话,以后就很难去沾一下 福 字 的灵气了。2006在封碑前,工匠们集中拓了一部分的字。这些字经过精心的装裱,现在正在限量发售当中。不得不承认这个导游水平高,讲解得好,很好地掌握了大家的心理--很多人都买了手拓的福字,要不是穷学生的话,我也想买一份了。
在进入假山下面的山洞里面摸 福 之前,我们先走了一遍连接蝠厅的长廊。据导游讲,这段长廊记录着和珅的发迹之路,所以走的时候非常有讲究。
首先,从西边的口上长廊,长廊刚开始的地方有两处有石阶的地方,这些地方都要跨石阶而过,意味着跨过坎坷;然后上长廊的时候已经要直直往前走,千万不能回头。听着挺玄的阿,我们都照着导游说的到了蝠厅-那是和珅赏月的地方,下面的假山里面就藏着福字碑。这地方很隐秘,而且是在龙脉之上,连后来嘉庆都不敢动,所以这里的建筑才保存的如此只好。
下面的福字碑据说是周总理发现的,他看到假山上有一个双龙戏珠的图案,就对随从说,有龙的地方必有皇家之物,后来果然在双龙戏珠的珠子的正下方发现了这块碑。可惜,国宝保护的不好,以前毫无节制的拓字和游人接触造成了严重的损坏,现在我们去的时候只能隔着玻璃与福字碑接触了。
导游告诉我们,摸碑的时候也要有讲究的。首先是要用右手摸,摸的时候要先摸玉玺的印章,然后再摸整个字;因为这个字蕴含的深意很多,“多子,多才,多田,多寿,多福“,要全部都沾上也挺难的,就看大家最想要什么了,就可以
摸对应“多子,多才,多田,多寿,多福“的部分了,最后模完之后要把福气放到口袋里面才好。过程很顺利,唯一不爽的就是有两个保安在碑前面一直推着有人往前走,与福字碑的接触时间很短。
恭王府花园还有很多地方值得一看,比如妙香亭,戏楼,门口的一段小长城。院子里的湖,湖心是湖心亭。湖水还算清,里面有很多大大小小、各种颜色的鱼,值得一看。
在走之前,我们特意去流杯亭去温习了一下。坐在出水口的地方,两脚踩在出水口的两边,这样就能够得福得寿啦。可惜人太多了,一波一波的人流涌过来,挤的我们很快就走了。这会儿可能太晚了,还是有些导游不上心?反正她们只是简单介绍了一下这个亭子就把游客们领走了;和我们跟的导游相比,差的太远了。
出来的时候已经5点了,但是花园门外面贴着墙根,游客们还排着长长的队伍,看上去大多数都是旅游团的。不过这么晚了,进去游玩的时间肯定很紧,导游们怎么可能这么短时间内把经典的景致都介绍完呢?
接着我们去逛了一下什刹海的前海、后海;边上林立着酒吧--我感觉真是刹风景,就不提它们了。
总体来说,恭王府花园是一个非常值得推荐的地方,浓重的文化气息,加上幽静的环境。很值得一游。