2012总结和2013计划

2013年已经过了4天,我也对我的2012年做个总结。

------------------------------------------------------------

总的来说这一年还是比较忙碌的:上半年在上课,暑假在搞项目,下半年开始做些真正偏向研究的东西。

之所以把上课这件看似和研究生没多大关系的事情联系在一起是因为我上半年的确没干过什么正经事——至少在结果上是这么看的。算法课的收获微乎其微,现在还能说的出口的就是我总算搞清楚了NP(完全/难)问题究竟是什么玩意儿;程序语言理论没学好的确是一大憾事,我到现在还没有把operational/axiomatic/denotational semantics给理清(居然还写了一篇review,WTF);英语是永恒的痛哪,貌似自从读研以来英语就从来没给我好脸色看过,看来是得在这上面上花点功夫了。分布式系统现在依稀记得的就是曾经写过一段MPI的代码但已经找不到src了,然后就是cloud backup了,总的来说从这作业上还是有点收获的(尽管看起来挺傻B的,尤其是MPI的那一坨)。cloud backup我主要是打下手的,因为我对Web的知识真的是捉襟见肘(到现在为止仍然是);不过我至少稍微了解到了神马是实际一点的开发(这是在往自己脸上贴金吗=  =),以及它并非我想象中的那么难。软件测试很水,不过在这门课上我第一次独立写了一段不那么toy的片段(尽管没有多少含金量)。除此之外,我能想象得到的还能说的就是我自己折腾了几个LaTeX的模板,其间被LaTeX这种古老而又神奇的家伙虐到不行了。

六月份开始干项目的活,传说中这个项目是973的,然后无缘无故最终在书面上看到的是“自然基金”;原先是北大和交大(两个实验室)合作的科研项目,按照现状来看,呵呵呵;这是一个非常值得吐槽的玩意儿。倒是因此6月中旬去了一趟北京,然后在那里混了几天见了几个同学倒是蛮开心(只是时间有些匆忙有几个人没来得及去看太无奈了,亦已焉哉)。

我原本还感慨我读研这段时间估计是没法正经地用点C/C++了;不过9月份程哥给我抛橄榄枝,然后我就开始做一点真正偏研究性的东西了。整个开发环境都是在Linux下做LLVM的活,gcc的tool chains真的完全不熟啊;结果各种杯具。一下子发现Java/Python/Haskell这些应用级的语言实在是程序员的一种解脱啊,可以很少顾及底层。举个例子,一个困扰了我们几个月的编译错误,居然是由于Ubuntu的gcc 4.6.3的bug引起的;不由得想起了GPL当中一句非常木有节操的话:There is NO warranty.遇到这样的情况,也只好自认被坑了。项目还在进行,所以苦逼的日子还要继续,也就不说什么了。只是这个过程中我着实感觉到了做个研究不容易啊——程哥的六年博士生涯究竟是怎么活下来的啊!!!

上面就是我作为一个计算机/软件专业的研究僧做一天和尚撞一天钟的结果了。

---

以上只是我2012年的一个小小的方面;下面说点OT的事情。

这一年,我终于开始写起博客来了。尽管我以前也用过新浪、网易、CSDN、cnblogs、cppblog、ITeye和blogbus的博客,但是有的太不适合写点技术类的了,有的太过社区化,界面普遍设计得有中国特色的华而不实,而且最让人难以容忍的是定制性很差而完全是用的BSP的服务。is-programmer就好些,所以现在没事就在这里随便扯扯。后来知道了github提供了jekyll来写静态博客,所以就半抄半改了一个自己的(其间问了秦续业各种傻逼问题)。博客其实算不上是最好的交流方式,但是聊甚于无啊!

这一年我慢慢对wikipedia/wiki有了点兴趣——是用吃人家的嘴软用人家的手短的原因吗?并且真正打算做点贡献了。

学术上面才刚刚入门,谈何成就?现在只好对7月份的信誓旦旦自缄其口。代码上更是乏善可陈。

很诡异的是我这一年看得电影倒是不少,当然大部分电影的情节之脑残以致于我都是直接按着快进来看的;这一年里稍微有意义的书到真的没怎么看过,所以我现在都不好意思说自己是个文化人了。

---

下面模糊地提一下我2013年对自己的要求吧。顺便附一个链接:7 Habits of Highly Ineffective People

找一把锤子尽管2012年挺忙的,不过都虚有其表;本质上都做的是一些没有深度的事情。虽说君子不器,但是我现在更愿被称作瑚琏。宁可执有如须弥山,不可落空如芥子许。

调整好状态。2012年尤其是下半年我的作息时间大部分处于不正常状态(知道现在orz),而且情况越发糟糕。幸好每天干的事情所要的脑力不是很多——与其把coding作为一个脑力活倒不如说它是体力密集型的了。熬夜只能作为权宜之计,确实不能倚着年轻力壮透支自己;有时想想本科那段时间里的作息时间自己都瞠目结舌了。今年我必须考虑好作息了,要不真的会死人的!!!吾生也有涯,而知也无涯。以有涯随无涯,殆已;已而为知者,殆而已矣。何必为难自己呢?从今天起,如果没有特殊情况绝对不在1点之前睡!

从小事做起。感觉我总有点不修边幅,完全是一个典型程序员的形象。本科的时候因为是理科专业所以还是比较细心的,现在却都变得对外界反应迟钝了,自己做的事情也钻研不够(应该还是感觉不确定性太高了吧)。宿舍一团糟,恶习不改,行事不谨慎…做事不用心,全职当码农!

订计划。凡事预则立,不预则废。这个计划到不一定需要多么详细,但是却一定要反映出进步;不一定要有具体时间限制,但是却要有范围。Anyway,a goal is a dream with a deadline.

脸皮厚,嘴皮大,腿脚快。隐隐约约记得这是高中左老师说的一句话。刚读研的时候就有这个念头,并且在研一上学期还做得不错。然而,后来就又变得畏畏葸葸了。有什么观点都不敢提出来,这对研究或者工作什么的都不是好事。现在发现我已经成了一个非常不善言谈的人,而且在讨论时提不出什么问题了。直到前些日子程哥提起我才发现这个问题,并且在之后觉得后果很严重!

---

下面说说稍微实际一点的,然而具体的懒得列了。

  1. 基本技能
  • OJ上的一些水题 (+《编程之美》)
  • 学习C++(C++ gotchas两遍,再看一遍C++ primer)
  • 高级UNIX编程
  • 深入理解计算机系统
  • Java编程思想
  • 熟悉Scala的Play!框架并比较学习Python的Django
  • Javascript基础
  • 用markdown/wiki语法写点wiki页面
  1. 学业基础:
  • 熟悉GNU tool chains并看完《程序员的自我修养》
  • LLVM C++ API的分析相关
  • Scala编译器相关
  • 程序语言实现模式

Nonsense Comments(10) Sat, 05 Jan 2013 18:58:26 +0800

在C语言中模拟含有默认参数的函数

【好久没写了,来篇技术科普文】

写C++代码的时候总想当然以为C中也有含默认参数的函数这种玩意儿(值得注意的是Java也不支持C#支持,Scala这种奇葩支持是不足为奇的),然后在编译下面这段代码之后颜面扫尽TwT

#include "default_args.h"
void printString(const char* msg,int size,int style){
    printf("%s %d %d\n",msg,size,style);
}
int main(){
    printString("hello");
    printString("hello",12);
    printString("hello",12,bold);
}
#include<stdio.h>
enum{
    plain=0,italic=1,bold=2
};
void printString(const char* msg,int size=18,int style=italic);
nonoob@nonoobPC$  clang default_args.c -o default_args
In file included from default_args.c:1:
./default_args.h:12:42: error: C does not support default arguments
...

clang果然是人性化的编译器,还会告诉我们真实的原因;不像gcc只会报出一堆慕名奇妙的error信息,读者不妨自己尝试一下,这里就不吐槽了。至于如果我们的目的在于只要编译通过的话,那完全可以无节操地把这段代码当成C++代码,然后用clang++或g++来搞定这一切;最多只是会报出一个warning(而如果把default_args.c换成default_args.cpp的话连clang++都不报任何警告):

clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated

传说中程序员只关心error而不管warning,那大可就此打住并到stackoverflow的这个thread上灌水一番。不过如果是那种闲着无聊且非常执着的话(或者是那种没法用C++而只能选择C的情况,抑或是那种考虑到在其他C的源文件中用到printString()函数的情况),那不妨往下看。一个很容易想到的解决方案自然是重载函数了(先不管效率)。在default_args.c删掉函数中的默认值并添加下面这段:

void printString(const char *msg,int size){
    printString(msg,size,italic);
}

但却是:

nonoob@nonoobPC$  clang override_args.c -o override_args
override_args.c:14:6: error: conflicting types for 'printString'

又一次颜面扫尽,C原来连重载函数都不支持>_<,弱爆了。没辙了吗?就不能猥琐地模拟一下然后让C语言程序员也享受一下默认参数的快感吗?macro!C程序员的必杀技,一个被C++程序员吐槽无数的招数:-(,但却是一个很优雅的解决方案^_^

#include<stdio.h>

enum{
    plain=0,italic=1,bold=2
};

void printString(const char* message, int size, int style) {
    printf("%s %d %d\n",message,size,style);
}

#define PRINT_STRING_1_ARGS(message)              printString(message, 18, italic)
#define PRINT_STRING_2_ARGS(message, size)        printString(message, size, italic)
#define PRINT_STRING_3_ARGS(message, size, style) printString(message, size, style)

#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
    GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
                PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )

#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

int main(int argc, char * const argv[]) {
    PRINT_STRING("Hello, World!");
    PRINT_STRING("Hello, World!", 12);
    PRINT_STRING("Hello, World!", 12, bold);
    return 0;
}

看到这么一坨代码,估计没几个人喜欢——宏这种对把源代码看成白盒的程序员实在不友好的东西,然而却让所有的C程序员大受其益。不妨看一下NULL的定义:

#define NULL ((void *)0)

闲话不扯了,看看前段代码是怎么回事;毕竟子曾曰过:举一隅不以三隅反,则不复也。

macro本身也不是什么见不得人的东西,说到底就是方便程序员偷懒的,在实现的最终目的上和函数没有本质区别。这里需要注意的是__VA_ARGS__这个东东。其洋名叫Variadic Macros,就是可变参数宏,在这里是配合“...”一起用的。可变参函数想必C程序员都不陌生,就是没吃过猪肉也见过猪跑是吧,比如printf;这里也有个tutorial。我们在这里需要知道的是宏定义(define)处的“...”是可以和宏使用(use)处的多个参数一起匹配的。下面以PRINT_STRING("Hello, World!", 18);为例说明是怎么展开的。

首先"Hello,World!", 12匹配PRINT_STRING_MACRO_CHOOSER(...)中的"...",于是被扩展成:

PRINT_STRING_MACRO_CHOOSER("Hello, World!", 12)("Hello, World!", 12);

PRINT_STRING_MACRO_CHOOSER("Hello, World!",12)又被扩展成

GET_4TH_ARG("Hello, World!", 12, PRINT_STRING_3_ARGS, PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )

所以整条语句被扩展成了

GET_4TH_ARG("Hello, World!", 12, PRINT_STRING_3_ARGS, PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )("Hello, World!", 12);

接下来看到的是匹配#define GET_4TH_ARG(arg1,arg2,arg3,arg4, ...)arg4的情况,"Hello,World!"匹配args1,12匹配arg2PRINT_STRING_3_ARGS匹配arg3PRINT_STRING_2_ARGS匹配arg4,而其余, PRINT_STRING_1_ARGS, 的部分匹配了“...”,所以经过这一番扩展变成了

PRINT_STRING_2_ARGS("Hello, World!", 12);

即为

printString("Hello, World!", 12,1);

这样一番折腾终于见到庐山真面目了。当然我们可以用gnu cpp查看一下预处理的结果是不是这样的(一般来讲C和C++用preprocessor是一样的)。

...
int main(int argc, char * const argv[]) {
    printString("Hello, World!", 18, italic);
    printString("Hello, World!", 12, italic);
    printString("Hello, World!", 12, bold);
    return 0;
}

这也解释了为什么说用macro的解决方案是优雅的。不妨再看看生成的llvm的ir形式:

nonoob@nonoobPC$  clang macro.c -S -o - -emit-llvm
; ModuleID = 'macro.c'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
target triple = "i386-pc-linux-gnu"

@.str = private unnamed_addr constant [10 x i8] c"%s %d %d\0A\00", align 1
@.str1 = private unnamed_addr constant [14 x i8] c"Hello, World!\00", align 1

define void @printString(i8* %message, i32 %size, i32 %style) nounwind {
  %1 = alloca i8*, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  store i8* %message, i8** %1, align 4
  store i32 %size, i32* %2, align 4
  store i32 %style, i32* %3, align 4
  %4 = load i8** %1, align 4
  %5 = load i32* %2, align 4
  %6 = load i32* %3, align 4
  %7 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i8* %4, i32 %5, i32 %6)
  ret void
}

declare i32 @printf(i8*, ...)

define i32 @main(i32 %argc, i8** %argv) nounwind {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i8**, align 4
  store i32 0, i32* %1
  store i32 %argc, i32* %2, align 4
  store i8** %argv, i8*** %3, align 4
  call void @printString(i8* getelementptr inbounds ([14 x i8]* @.str1, i32 0, i32 0), i32 18, i32 1)
  call void @printString(i8* getelementptr inbounds ([14 x i8]* @.str1, i32 0, i32 0), i32 12, i32 1)
  call void @printString(i8* getelementptr inbounds ([14 x i8]* @.str1, i32 0, i32 0), i32 12, i32 2)
  ret i32 0
}

很清爽的代码,令人心旷神怡吧。

废了这么大的力气才做了这么点事,还不如不用“默认参数”呢是吧?但是当把这个写成库的时候,或者以后要经常使用的话这就方便多了,且不容易出错!

为了无聊起见,再看看default_org.h+default_org.c用clang++/g++编译得到的llvm的ir:

nonoob@nonoobPC$  clang++ default_args.c -S -o - -emit-llvm
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
; ModuleID = 'default_args.c'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
target triple = "i386-pc-linux-gnu"

@.str = private unnamed_addr constant [10 x i8] c"%s %d %d\0A\00", align 1
@.str1 = private unnamed_addr constant [6 x i8] c"hello\00", align 1

define void @_Z11printStringPKcii(i8* %msg, i32 %size, i32 %style) {
  %1 = alloca i8*, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  store i8* %msg, i8** %1, align 4
  store i32 %size, i32* %2, align 4
  store i32 %style, i32* %3, align 4
  %4 = load i8** %1, align 4
  %5 = load i32* %2, align 4
  %6 = load i32* %3, align 4
  %7 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i8* %4, i32 %5, i32 %6)
  ret void
}

declare i32 @printf(i8*, ...)

define i32 @main() {
  %1 = alloca i32, align 4
  store i32 0, i32* %1
  call void @_Z11printStringPKcii(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0), i32 18, i32 1)
  call void @_Z11printStringPKcii(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0), i32 12, i32 1)
  call void @_Z11printStringPKcii(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0), i32 12, i32 2)
  %2 = load i32* %1
  ret i32 %2
}

从这里的IR中我们至少可以得到两点信息:

  • C++编译得到的函数名和C编译得到的不一样(事实上是很不一样,可以参见name mangling),使用c++filt之后我们可以看到C++中的printString的签名实际上是void @printString(char const*, int, int)(i8* %msg, i32 %size, i32 %style)而不再是void @printString(i8* %message, i32 %size, i32 %style)。同时这也解释了为何在C中不会有函数的(静态)重载(没有OO自然动态重载更无从说起)——假设C有函数重载的话,会生成三个同名的函数,而C中调用函数时仅仅根据符号表中的函数名,这样就会造成混乱。【TODO:动态重载实现机理】
  • 编译得到的代码中是看不到任何默认构造函数的信息的(同样连enum的信息也没有了),3条call指令中我们得到的只不过是对应下面源代码的指令(也没有生成三个签名不同但名字相同的函数printString())。
​printString("hello",18,1);
printString("hello",12,1);
printString("hello",12,2);

到此为止,正文结束。下面贴捣鼓的一段含宏的代码~~

#include<stdio.h>
#include<stdarg.h>

#define LOGSTRING(fm,...) printf(fm,__VA_ARGS__)
#define MY_DEBUG(format,...) fprintf(stderr,NEWLINE(format),##__VA_ARGS__);
#define NEWLINE(str) str "\n"
#define GCC_DBG(format,args...) fprintf(stderr,format,##args)
#define DEBUG(args) (printf("DEBUG: "), printf args)
#define STRING(str) #str
#define NULL 3

int main(int argc,char**argv){
    LOGSTRING("Hello %s %s\n","Hong""xu","Chen");
    MY_DEBUG("my debug")
    GCC_DBG("gcc dbg\n");
    int n = 0;
    if (n != NULL) DEBUG(("n is %d\n", n));
    puts(STRING(It really Compiles!));
    return 0;
}

 

参考资料:

  1. http://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros
  2. http://www.cnblogs.com/alexshi/archive/2012/03/09/2388453.html

Programming Comments(18) Tue, 18 Dec 2012 23:49:24 +0800

这几天的自省

研二两个月了,时间过得太快。没有课的日子,远远不是以前的我可以想象的,其实现在也没想清楚。

别的不说,这六十天左右的时间里,我的作息时间越发不正常了——看来暑期还只是前兆,感觉现在早于一点睡的都很少了。刚开始还是按照google calendar安排的,可是由于或这或那的原因,经过三天的特殊情况,我终于沦陷了。之后就把以前订的作息时间当成累赘;偶尔听听国内又传来某公司程序员过劳死之类的话,已经有些麻木。老爸老妈的谆谆教诲,听的时候还有些羞恶廉耻之心,过后依旧我行我素。打死我也不会想到现在有时候居然是两点、三点甚至四点才睡;然后忽然发现我在透支自己。

一次两次的错误作息时间或许不算什么,但问题不在于这是一次两次。七八月份就意识到这样的话,长此以往,我将不我;现在看来,搞不好的话一语成谶。现在白天就远远没有本科时候清醒了——大概堕落成coder之后就没怎么认真动过脑筋吧;之后接踵而来的就是恶性循环。白天的任务拖到晚上,晚上拖到很久,就寝时间再创新高,第二天周而复始;生产效率之低令人咋舌,期间又养成了不少恶习。又由于计算机技术这个大的方向其实是比较远离书的——读在线文档、写代码的时间往往占了大多数;互联网的魅力又让人身陷其中难以自拔。这样说来,“大道以多歧亡羊,学者以多方丧身”这话最需要记住的是我们每天坐在电脑桌前的宅男。兴趣是个好东西,当拼命三郎精神也可嘉,但是一旦不顾生活规律的话,后果不堪设想。

这两个月以来,我觉得值得骄傲的是终于把我的网络足迹统一起来了。干掉了新浪微博和知乎,这个世界一下子清净了许多——其实这两者也没什么不好,只是现在的确不适合我;豆瓣里关注的人我也狠心删掉了一些——太多没有见过真人的人之间相互关注相互吹捧实在是一件比较扯淡的事情,而且是在一个不是以讨论为中心的大环境中;以前我还以为我能扛得住豆瓣的文艺气息,现在发现我弱爆了,耳濡目染,谁都不能免俗。另外,我很欣喜地是终于将google reader的订阅量减少到了1024;rss订阅博客的确是我见到的最能提高自己见识的上网学习方式了;可是和一般快餐文化一样,内容毕竟还是缺乏条理性。会有些文章让人打开眼界或者起到指点迷津的用途,但是说起系统性和深度还是不够的。原本我打算因此而放弃写些不成文的内容的,不过对我来说现在到了output的时候了(以前我总拿厚积薄发来为自己辩护,现在才知道完全是bullshit);所以以后继续把这里当成我的实验田吧。另一件事是我终于开始慎重对待我的网络形象了,比如我的id现在都改成了正规的了。作为ds如果总是做ds才做的事那可就真的无法自拔了。

陶渊明曾把他以前求仕生涯归结为“悟已往之不谏,知来者之可追”,我对以前的所做也抱有这个态度,并且开始洗心革面。

但愿今天是我最后一次无故晚睡!

Nonsense Comments(10) Sun, 28 Oct 2012 00:57:18 +0800

《儒教三千年》笔记

书的简介见这里,内容见书本身。然而除了有些八卦之外,这篇笔记和书内容关系却不大。

---

按照陈舜臣的说法,儒并不是孔丘所创,孔子只是集大成者——有点像光头僧侣并不是佛教首创,但却是因佛教而流传一样。孔子出身在鲁国这样一个伯禽的封地,地方虽小却很重周公所推崇的礼教;孔子四处游学讲说,布道授业,的确辛苦了。以前我一直不明白的是为什么儒家这么重“礼”,从这本书中才了解了个大概:原来以前的儒者都是靠丧葬祭祀混饭吃的,对他们来说这才是安生立命的根本,也是因为这个原因他们才会东奔西走——要不会失业的!从孔子的言语来看的确可以发现有不少假托周公的话——不排除有些的确是周公旦提倡的,但不免有仲尼自己添油加醋的成分,即使有时候连他自己也没有察觉。本来嘛,找个公认的牛逼人物傍一下大腿就是人之常情,就连贾宝玉也会用《古今人物通考》中的“西方有石名黛,可代画眉之墨”不是?顺便扯一点,关于华夏究竟有多少年的历史的问题我更倾向于从商开始算。司马迁有文学家的修养但的确不是一个严谨的史学家;居然有以《上下五千年》为名的畅销书,足可以用“呵呵”来形容国内的历史学;管窥蠡测,五四新文化思想现在可算是荡然无存了。

讲儒家,《论语》和孔子是绕不过的。如果想研究孔子的言论,论语和孔子家书以及相关史书作参考应该也可以八九不离十了;但如果想研究孔子之后的儒家学派,可就要了解历代文人学者理解的四书五经和他们的言行著述了;如果要分析儒学对所谓的华夏文明的 影响,涉猎之广就非鄙人所能想象了(不过也可以“站在巨人的肩膀上”)。如果真有哪个像我这样的门外汉一本正经的讨论第三者,我的第一感觉肯定是:亲,吃错药了吧?还好我上面说的三者都不是,我只是闲扯的;而陈舜臣老先生自然也不是门外汉并且也是以茶话闲聊为主。

从这本书中,我发现日本学者研究《论语》可不像国内的那么死板,南怀瑾对"有朋自远方来,不亦乐乎"的调侃居然可以被当成辫子揪来揪去——本来就是(现在一般人理解的)“别裁”嘛(也有人拿《论语别裁》的标题声讨,不过也许是媒体大肆扭曲事实)。如果被理解成"有朋,自远方前来比较"是不是会被某些人骂死?再有荻生徂徕把“达巷党人”说成是一个姓达巷名党人的意思,他死定了!不难发现在我们现代人所说的中国古代也存在了好些解释,不少解释当然是比较牵强的;然而由于古汉语的语法的混乱、通假字的乱用以及不带标点等种种弊病,造成了在字面上很多解释居然都是可行的!现在有了些主流的解释,可是它们绝不是标准答案,我们更不应当以此来否认其他的解释的合理性啊!况且,“一千个人有一千个哈姆雷特”,鬼才相信世界上有两个人可以对同一个句子有相同的理解呢(相似而已,如果用隶属度来说的就准确多了)!

吐槽一下孔子。小时候总是听长辈说"孔老二"、“迂夫子”这样的话,但是高中时读论语的时候从来没把这和孔子联系起来。知道大一的时候才想起来,感觉孔子真的有些迂腐——不过程度并不特别深(其实《论语》中就有不少可以体现孔子本人也非呆板的言行),而只是在我把他和他的学生胡乱分析了一下之后有的一点小结论。初中听老师说孔子“弟子三千、贤者七十二”;当时有个念头是孔子真牛逼,特地凑成这么好两个的数字。知道大学才意识到原来古中国人和古印度人真的对数字没什么认真劲儿,而为了求得辞藻、押韵等古人又可以随便用些词语。弟子三千,按孔子活了七十六岁的说法,他平均每九天收一个弟子;很多弟子还指望从孔子口中得到些什么吗?最多只是间接传授罢了;或者又把那些“一字师”和自诩为门人的加了进去。贤者七十二,当然也不好考证了。但我们知道的是颜回、曾参、子贡、子路、子游、子夏名额肯定是有的,我想宰我、冉有、樊迟等人必然也是位列其中。但据论语所记,冉有是一个非常喜欢敛财的人,而且还帮着季氏!用后世儒家的观点来看,怎么都跟贤不沾边啊。再看子路,作为一个类似绿林好汉出身的大老粗,能虚心接受孔子的教化,不得不说精神可嘉,并且其赤子之心着实令我喜欢;可我们看到的是子路仍然是一个非常鲁莽、不喜思考的人(不妨想想他是怎么死的),称之为贤者也有些过誉了吧。樊迟则有传说说他贪图安易,追求物质利益。我从没有抱着贤人不能有错的观点,可这三个人用“贤者”形容的确不妥吧。不过我认为最值得吐槽的是孔子对颜回的厚爱,简直到了不可理喻的地步。从论语中可以看到的关于颜渊直接的描写并不多,他是个“神秘人”——我们只知道“回也不改其乐”、“吾与女弗如也”;而颜回对孔子却是“仰之弥高、钻之弥坚”,”子在,回何敢死“之类马屁不能拍得再露骨的话了。孔子钟爱他,大概是从他身上看到了一个更为迂腐版的自己,又或者是颜渊死得早老夫子容易伤感吧。相比而言,端木赐倒是一个机智、聪明、真诚、有为的人。比如他可以通过问"伯夷叔齐何人"而举一反三得到"夫子不为也","子贡使楚"的故事也广为人赞,可认为君子不器的孔子仍然认为子贡“瑚琏也”——最让人肃然起敬的是子贡可以在孔子去世后在孔子墓旁守孝三年——这种事只有子贡做出来了,即使曾参这样的人也没有做到!我总想为子贡抱不平,有时不禁想孔子是嫉贤妒能才有意贬低子贡的吧!然后我们再看看孔庙的"四配",颜回、曾参、孔伋、孟子!曾子却是孔子得意门生,并且带头整理孔子言行,功不可没。孔伋是孔子的孙子,传言是《中庸》作者。孟子亚圣自不必说,尽管其言论和孔子的观点分歧并不少见。可是颜回何德何能位居护法之首?所以说呢,很多现有的观点都是值得怀疑的,想我国古代把儒学和国家等身的做法如果完全没有佛教和道家补充的话实在是件很危险的事情!

再扯一句,如果宰我没有落下昼寝的恶名的话或许国人的理性思维远比现在高很多;如果孔子少些对从商的端木赐偏见的话中国或许早就摆脱了农业为主的经济;如果孔子在编纂《易经》时对“形而上者谓之道、形而下者谓之器”这种说法有个比较好的解释的话中国也就不会变成技术落后的国家了……蝴蝶效应下一切都有可能;只是历史已经不可以改变了。

Nonsense Comments(34) Sat, 20 Oct 2012 01:44:02 +0800

书、人和佛教略评-《金刚经说什么》读后感

 

没有力荐这本书是因为我对南怀瑾及佛教有疑惑。我看的 是老古出版社刘雨虹整理的《金刚经说什么》的简体电子版。

————————————————————

先说书。

禅宗经典金刚经+南怀瑾教学讲义+出版社的细心整理,单从表达金刚经的内容来看这本书非常不错。以前我看到的不少南老师的言论都出自这本书中,也曾经疯狂推崇南老师这样一个禅门大学。我想现在如果一个世俗的人想从经文出发来理解金刚经,这本书应该成为必读之物。至少读完之后,可以说我读过《金刚般若波罗蜜经》之类的话;并可以把“应无所住而生其心”,“若以色见我,以音声求我,是人行邪道,不能见如来”,“一切有为法,如梦幻泡影,如露亦如电,应作如是观”等作为口头禅来反驳那些迷信的人了。

以前我一直把这本书看成和佛教经典一般神圣的玩意儿,想找个庄严的场合抽出一些时间来专心研读;因此我一直没有机会看到这本书的全部内容。不过这次看书,我可完全没有以前的虔诚了——完全只作为打发时间的闲书,并且有时是作为厕读物!所以如果有人说我毁佛谤佛的话,现在就可以声讨我;而我也是抱了“我不入地狱,谁入地狱”的心的。

读这本书的过程中我的感受反而是在书外,完全的书外;因为读书的过程让我明白了一个浅显的道理:只听一面之辞肯定不对。以前我只是从别人口中知道南怀瑾老师多么博学,只是看到他的一些比较著名的话(诗句),就对他推崇至极。但当我真正把这本书看到三分之一的时候,我才意识到之前的一些观点只是我的一厢情愿,我受断章取义荼毒太深了!在《金刚经说什么》中,南老师的确有很多经典的句子,很有启示意义;但是必须承认的是,其中也有很多不那么由衷的话,当然也有那些由衷的却不尽然正确的话。

比如,对于经文中对于“如来”,“世尊”,“我”等不能混用的讲究,说出来实在是画蛇添足;这不禁让人联想起中学语文阅读理解中的惯用题目:文中的xx为什么不能换成xx?写作的过程我们都会遇到遣词造句的问题,但最终选定的哪个词可能恰恰就是因为个人喜好——毕竟词语是无法完整表达真实意境的,最多只是逼近。我们无法得知迦叶尊者在整理佛陀言论的时候的想法,也无法得知鸠摩罗什三藏法师在翻译经文时的想法;同时我们也无法得知迦叶与释迦牟尼之间的理解是否一致,鸠摩罗什的年代距离佛陀在世时的梵文词义变化,经文译完之后汉语的词义变化。这么多不确定的因素在一起,足以让我们现在理解的佛陀的想法和现在我们看到的金刚经的句子相差很大。另外,如果考虑到一个人时间段内的想法的差异的话,那或许只能用“拈花微笑”(或许应该是哭笑)来应对经文中的意思了。过去不可得,现在不可得,未来不可得。当然,研磨词句是必要的,但是对于经中的句子都这样掰(尤其是这些本来意思就含糊的词),不难看出南老师太吹毛求疵了。

南老师在书中喜欢用现代的眼光来看待佛教,我个人认为这非常好!但是用一些物理、生物、地理的看似正确的例子来解释经文中的句子,就显得太勉强了。扯到什么“原子”、“分子”之类的话,多少有些故弄玄虚;释迦牟尼佛当时的世界观没有意识到这些的存在大概是必然的吧;如果真有,大概只是类似德谟克利特等人理解的原子论吧。如果有人猜测世尊“悉知悉见”的话,一个明显的反驳的理由就是为何世尊当时没有将植物当成众生来看?当然,南老师很可能是以一种调侃的口吻来说的,毕竟《金刚经说什么》只是根据南怀瑾的讲习授课整理的,而南老师本身就不是那种拘谨的道学家。然而,对于我这样被一个理性冲昏头脑的人来说,总感觉不合时宜。南老师用地外生命来解释“三千大千世界”,并再一次赞扬了释迦牟尼一把,这样的理解是不是太机械了点?总感觉南怀镜老师喜欢给佛教贴上”科学“的金,但是这两者实在不应该有太多的联系。不过南老师在说“须弥山是不是珠穆朗玛峰“的问题上可没有和其他一些学者一般固执,话说那些学者研究这种问题的学者也真够无聊的。

南老师在有些场合也会说佛教经典有点自卖自夸的成分,比如经中”其福胜彼“之类的话时,南老师也调侃了一下——这大概有种无奈吧——不能直言说出,却只能带有戏谑地委婉道出。另外,南老师在讲经的时候也出现了前后不一致的问题,比如在金刚经对“空”的理解上,前面说此经不是讲空的,后面又着重强调空,最后又提到“不住”才是主旨而不是“性空”。并且在功德、福德上,南的说法也有些出入。当然以此说书讲得不对肯定是错误的,连佛陀都在《金刚经》中把他说法四十九的话都给推翻了。

再次声明,指出这些并不是说书不好,只是部分说法值得商榷。

————————————————————

说说南怀瑾其人。

南老先生前几天(2012.9.29)刚去世,祝老先生一路走好。

很多人说南老师是国学大师,却也有人说其是江湖骗子。不禁想起了Bjarne Stroustrup的一句话:There are only two kinds of programming languages: those people always bitch about and those nobody uses。

对人也一样,所以人怕出名猪怕壮——正如南所说:清福才是真的福气。

南怀瑾的言论中的确犯过些错误,张中行对《论语别裁》中的不少说法都有批评(我没看完,没资格说太多),比如“毋友不如己者”,作为一个研究者指出异见是必要的,应该赞扬这种做法。但有人因此而得出南怀瑾是骗子就不对了。闻道有先后,术业有专攻。人非圣贤,怎么能什么都对呢?(乱入:“圣贤”这词有误导作用,建议文化部取缔或不建议使用)认为一个人牛逼就认为他在各个方面都牛逼,这个人肯定在意淫。由此可得,因南怀瑾讲经说错而说他不学无术的人的想法肯定是有问题的。

有人批评南在讲习佛教的时候,总喜欢把道教、儒教、基督教的理论掺和进来,不伦不类,并嗤之为外道邪魔。有这种念头的人肯定没认真考虑过佛教是什么。为什么要认为拉开教义之间的间距呢?又是出于什么原因有各种信仰呢?尽管有一点卖弄文学的意思,但是南在这点上的做法我举双手赞成。

有人说南怀瑾喜欢附势,玩弄权术;还有人说南怀瑾假借双修之名行淫乱之事。以我的粗浅的见解,我认为这是存在的;毕竟无风不起浪。凭我仅从网上得知的结果,我至少可以确定的一点是南老师并不是我以前想象中的那样伟岸;至少他在我心目中不再是神坛上的人物(任何人都不应该是,之前有这种想法只能说明我太肤浅了!)。他的所说与所作有些出入。如果确实程度如贬损南怀瑾的说法的话,那光淫乱之事足可以说明他非善类;不过如果只是俗人不了解真谛而诬陷的话,那就另有一说了。天涯上有个帖子的一段深合我意:

  • 姑娘已经过河走远了,师傅已经放下了,想不到徒弟还抱着呢!
  • 师傅有没有放下,只有师傅自己知道,徒弟虽没放下,但至少徒弟说真话了。怕就怕师傅其实也没放下,还故意教训徒弟要放下,那不是误人子弟的师傅吗?至少是虚伪的师傅,对不对?

这个问题上,还是得套用南老师的那句话“清者自清,浊者自浊”;如人饮水,冷暖自知。

————————————————————

扯几句佛教。

佛教没有宣传中的那样神圣。因为南怀瑾的事我无意中八卦出“佛陀和观音哥哥的性能力比较研究”这篇文章并坚持看完了!锁骨观音、鱼篮观音等故事想必都有耳闻(我也听说),佛祖的那个故事应该也是有的(毕竟作者贴出了经文的原文)。再联系佛教的起源,十八罗汉,维摩诘,龙树菩萨等人物故事,我相信这些都是经典上实实在在存在的。可恨的是那些神化、美化佛教的人!同时,我也认为汉传佛教(禅、净、律为主)和原印度的佛教在形式和内容上差异很大;至于说为什么还称为佛教,大概是因为外来的和尚好念经吧。

个人愚见,佛教真正告诉我们的是要发善心、不盲目;但言下还有个程度的区别。所以如果要称自己相信佛教的观点的话,少作恶少迷信才是正道;把这样的观点传播开来,那就功德无量了。

Nonsense Comments(48) Tue, 02 Oct 2012 12:23:30 +0800