2006-04
26

学过C++的人都应该知道C++中有个虚函数的概念。而在php5中如何实现这个虚函数呢?请看下面的代码:

<?php
 class A {
    public function x() {
        echo "A::x() was called.\n";
    }
    public function y() {
        self::x();
        echo "A::y() was called.\n";
    }
    public function z() {
        $this->x();
        echo "A::z() was called.\n";
    }
}
class B extends A {
    public function x() {
        echo "B::x() was called.\n";
    }
}

$b = new B();
$b->y();
echo "--\n";
$b->z();
?>

该例中,A::y()调用了A::x(),而B::x()覆盖了A::x(),那么当调用B::y()时,B::y()应该调用A::x()还是B::x()呢?在C++中,如果A::x()未被定义为虚函数,那么B::y()(也就是A::y())将调用A::x(),而如果A::x()使用virtual关键字定义成虚函数,那么B::y()将调用B::x()。然而,在PHP5中,虚函数的功能是由 self 和 $this 关键字实现的。如果父类中A::y()中使用 self::x() 的方式调用了 A::x(),那么在子类中不论A::x()是否被覆盖,A::y()调用的都是A::x();而如果父类中A::y()使用 $this->x() 的方式调用了 A::x(),那么如果在子类中A::x()被B::x()覆盖,A::y()将会调用B::x()。

上例的运行结果如下:

A::x() was called. A::y() was called. 
--
B::x() was called. A::z() was called. 


2006-04
10

从C FAQ上看到的一个程序,可以将C语言源文件变成难以识别的代码。文件从http://www.faqs.org/ftp/usenet/comp.sources.misc/packages/opqcp/下载得到。



2006-04
10

从水木精华区看到的,作用是求比 x 大的最小的 2的幂的整数倍,其中 n 必须为2的幂。简单地说,这个宏是用来对齐的。比如 _ROUND_UP(7,4)=8, _ROUND_UP(7,8)=8 等。

#define _ROUND_UP(x, n) (((x)+(n)-1u ) & ~((n)-1u))


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
25

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


2004-07
04

Windows下最基本的窗口程序。
阅读全文 »