2005-12
13

转载该文章并加上自己的注释。原文为 MVM 所作,郁也风加了注释。

MVM原作:http://blog.joycode.com/mvm/archive/2004/05/19/21899.aspx
郁也风注释:http://someok.blogbus.com/logs/2004/06/243128.html

charlee:我来说说日本的软件开发情况。我做的项目内容是嵌入式开发。

郁也风:MVM曾经发了篇题为《如何用正确的方法来写出质量好的软件的75条体会》的blog,后来他又给出了相应的回答:《七十五条》的解释 。而我亦给出了我自己的答案,有些不错,有些差强人意,有些则非常不足了。为便于比较,我的答案附在了MVM答案的后面。

阅读全文 »

2005-12
13

  1. 前言

  本人曾就职于多家公司,但留给我印象最深刻、开发管理最规范的公司是I公司。该公司总部位于美国硅谷,其开发的产品曾获得PC Magazine的最高五星级的优秀好评。现我根据在此公司中所感受到的经历及自身的一些感想写出来,希望能给大家和其它公司有所借鉴。

阅读全文 »


2005-11
29

研究发现,将英文单词的首尾字母之外的其他字母随机调换顺序,人还是能够基本无障碍地阅读整篇文章。例如,

Sometimes w3c's specification is much more insteresting than MSDN.
Unfortunatelly new techs are not supported by most browser.

将该文章中每个单词保持首位字母不变,中间的其他字母随机调换顺序,得到下面的文章。

Stmemieos w3c's seapifccition is mcuh mroe inseeirsttng tahn MSDN.
Urfnltueanolty new tcehs are not speproutd by msot bsrwoer.

但是大部分人仍然能够正常阅读。 做了个小程序用来调换字母顺序。



2005-11
29

我的开发环境是 MIPS_4ke,调试器是 Multi 2000 v4 + SlingShot + EJTAG。

昨天在调试程序的时候调试到这样一段程序:

UI8 * pDest = g_pStreamBuffer;
if (*(UI32*)pDest != 0x000001BE) {
  return;
}
pDest += 10;
if (*(UI32*)pDest != 0x000001B5) {
  return;
}

调试器跟踪到第二个 *(UI32*)pDest 时发生错误,调试器拒绝继续调试。开始百思不得其解,因为第一个*(UI32*)pDest正常地得到了所需要的结果。后来想明白,原来是对齐的问题。MIPS从内存中读取一个UI32时必须在4字节边界开始读取,而上面的操作执行了 pDest += 10之后,pDest就不再位于4字节的边界上,因此执行第二个 *(UI32*)pDest访问时发生了CPU异常。于是我做了下面的这个函数:

UI32 getUI32(UI8 * pSrc)
{
   return (
            (((UI32)(* pSrc   )) << 24) |
            (((UI32)(*(pSrc+1))) << 16) |
            (((UI32)(*(pSrc+2))) <<  8) |
            (((UI32)(*(pSrc+3)))      )
           );
}

这样就能够从任意地址读取四个字节了。

另外,Multi的编译器指令中有一个 pack 指令,该指令能够指定定义结构时的最小的对齐字节数。例如正常情况下进行下列定义时,各个成员所占定义如下所示:

typedef struct {
    UI32 a;        // 4 bytes
    UI8  b;        // 1 byte + 3 bytes padding
    UI32 c;        // 4 bytes
}

由于第三个成员 c 为 UI32,CPU在读取c时需要在4字节边界上对齐,因此成员b后面就留下了三个padding字节。如果这样写即可避免该问题。

#pragma pack(1)
typedef struct {
    UI32 a;        // 4 bytes
    UI8  b;        // 1 byte
    UI32 c;        // 4 bytes
}
#pragma pack()

但是这样一来,CPU读取c的时候为什么不会产生异常?其实编译器作了特殊的处理,它将读取c的指令分解成两条,第一条在前一个边界上读取c的前三个字节,第二条在后一个边界上读取c的最后一个字节,因此不会产生异常。



2005-11
07

前一阵子遇到的一个问题是,如何在Java程序中调用Windows DLL的函数。查了查资料,得知使用名为JNI(Java Native Interface)的方式可以让Java调用DLL中的函数。JNI的使用方法如下:

  1. 在Java中定义JNI调用,并撰写使用该JNI调用的相关代码。
  2. 根据定义好的JNI调用生成相应的C语言头文件。
  3. 利用上一步生成的头文件,使用C书写Windows平台上的代码。
  4. 编译C代码生成DLL库文件。
  5. 执行Java程序中JNI调用的代码。
阅读全文 »

2005-09
30

自己开设的服务器,希望晚上睡觉的时候它能自动关机减少噪音,早上起床之后再自动开机提供服务。我的主板是微星815EP Pro,Award BIOS v3.3(2001/4/20)。

首先重新启动计算机,按Del键进入BIOS设置。在BIOS下找到Integrated Peripherals中的PWRON After PWR-Fail,将其设定为On。这样停电之后再次供电时电脑就可以自动开机。

然后进入Power Management Setup,选择Resume By Alarm,将其设置为Enabled。然后将下面的Date(of Month) Alarm选项设置为0,表示每天定时开机。Date(hh:mm:ss)设置为开机时间,我设置为10:0:0。设置好之后重新启动计算机,进入操作系统,然后再关机。注意主板说明书上只说明了“修改后需要重新启动计算机”,要注意的是重新启动之后必须要进入操作系统,再关机,才会按照指定的时间开机。

然后设置自动关机。比较简单,在 /etc/cron.d 下面添加一个 shutdown 文件,内容如下:

30 2 * * * root /sbin/shutdown -h now

设置每天2:30定时关机。



2005-09
27

今天一个朋友问我,一个表有两个字段mac和ip,如何找出所有的mac相同而ip不同的记录?想了半天写出了下面的这个SQL语句。

mysql> select * from ip;
+-----+-----+
| mac | ip  |
+-----+-----+
| abc | 123 |
| def | 456 |
| ghi | 245 |
| abc | 678 |
| def | 864 |
| abc | 123 |
| ghi | 245 |
+-----+-----+
7 rows in set (0.00 sec)

mysql> SELECT  DISTINCT a.mac, a.ip
    -> FROM ip a, ip b
    -> WHERE a.mac = b.mac AND a.ip <> b.ip ORDER BY a.mac;
+-----+-----+
| mac | ip  |
+-----+-----+
| abc | 678 |
| abc | 123 |
| def | 864 |
| def | 456 |
+-----+-----+
4 rows in set (0.00 sec)


2005-09
25

本文总结了Java中很容易误解的一些知识点。
阅读全文 »


2005-06
10

我们原有的论坛使用的是基于 ASP 的 LeadBBS,后来由于服务器出现了一些小故障,导致 RegExp 对象不能用,于是论坛的许多用到正规表达式的功能全部失效。后来考虑将论坛整个转移到 PHP 系统上。而我维护的另一个论坛使用的是 NewvBB,这个系统是基于国外最流行的 vBulletion 修改而成的,该论坛相当成熟,管理功能也十分强大,于是就准备把论坛移动到 vBulletion 系统上。

目前面临的任务是 LeadBBS -> NewvBB。到网上查了一下资料,发现有关 LeadBBS 数据转换的程序很少,可能是由于在国内动网论坛独霸天下的原因吧。最后总算找到了一个 LeadBBS->phpWind 3.0的转换程序。经过进一步的调查,我决定了转换方法:LeadBBS -> phpWind 3.0 -> Discuz! 2.5F -> NewvBB 3.0。这样做起来相当麻烦,不过似乎是唯一可行的途径了。

1. LeadBBS->phpWind 3.0

这一步基本上没有遇到任何问题,简单地安装一个 phpWind 3.0,然后利用转换程序就能够把用户和帖子数据完整地转换过来。附件不能转换,不过算了,附件本来就不多,以后再慢慢手动修复吧。

转换后使用安装 phpWind 时设置的管理员密码进入 phpWind 的管理员界面,重新建立缓存。

2. phpWind 3.0->Discuz! 2.5F

这一步稍稍遇到一点困难。Discuz官方主页上找到的转换程序是 phpWind 2.0.1->Discuz! 2.5F的,直接利用该程序转换时,转换到第5步出现错误,说在 pw_tmsgs表中找不到用于 order by 语句的 id 列。查了一下数据库结构,发现 pw_tmsgs 中的字段名为 tid 而不是 id,于是修改转换程序的 340 行的列名为 tid ,于是转换成功。

转换成功之后试图登录管理面板结果失败了。查明原因,升级之后 Discuz! 原有的管理员的用户组id变成了普通用户,于是直接修改 cdb_members 表中 Admin 行的 adminid 和 groupid 列为管理员的相应值。管理员的用户组 id 可以在 cdb_admingroups 和 cdb_usergroups 表中找到。

修改之后即可成功登录管理员界面,重新建立缓存。

如果错误登录次数过多而导致被系统禁止登录,可以清除 cdb_failedlogins 表中的内容。

3. Discuz! 2.5F -> NewvBB 3.0

这一步也比较容易,直接利用留爱论坛上提供的转换程序即可成功转换。转换之后也同样遇到 admin 用户组变成普通用户的问题,修改 user 表中的 usergroupid 列即可。最后进入管理面板,更新缓存。



2005-06
08

昨天编译完binutils就一点多了,……困啊。今天继续。

首先需要把环境变量重新设置一下(因为昨天关机了):

 $ export TARGET=powerpc-kurobox-linux-gnu
 $ export PREFIX=/home/charlee/cross/tools 

然后我们准备开始编译gcc的第一遍。编译之前首先要准备好两个东西,一个是C语言库的头文件,一个是内核源码的头文件。昨天我们已经解压了glibc和kernel,现在只需要把这些头文件复制到目标目录下面就可以了。

 $ cp -a glibc-2.3.5/include/ $PREFIX/$TARGET
 $ cp -a linux-2.6.11.11/include/linux/ $PREFIX/$TARGET/include
 $ cp -a linux-2.6.11.11/include/asm-ppc/ $PREFIX/$TARGET/include
 $ cd $PREFIX/$TARGET/include
 $ ln -s asm-ppc asm

之后回到工作目录 /home/charlee/cross 下,为gcc建立编译目录:

 $ mkdir gcc-build-bootstrap

编译gcc:

 $ cd gcc-build-bootstrap
 $ ../gcc-4.0.0/configure --target=$TARGET --prefix=$PREFIX \ 
   --without-headers --with-newlib --with-gnu-as --with-gnu-ld \ 
   --with-local-prefix=${PREFIX}/${TARGET} --disable-shared
 $ make all-gcc

结果编译时报告 pthread.h 和 unistd.h 出错。