C的动态类型检查

这次美国之行的一大收获就是终于正视了Objective-C而不再只是当它是不顺手的工具了。这主要是有机会拜读了Brad Cox的《Objective-Oriented Programming, an evolutionary approach》。今天就谈谈它第91页提到的那个极少C程序员甚至C编译器作者知道的一个极为馄饨的语法:

struct MYSTRUCT someVariables;
someVariable = (*((struct MYSTRUCT *)(*)() _msg))(someObject, …);

C语言是静态类型检查的编译语言.例如下面程序定义和使用了两个类型:浮点和定点。

#include <stdio.h>

typedef struct {
    float x, y;
} FloatingPoint;

typedef struct {
    int x, y;
    int scale;
} FixedPoint;

int main() {
    FloatingPoint flo;
    FixedPoint fix;
    printf("(%f,%f)\n", flo.x, flo.y);
    printf("(%f, %f)\n", 1.0*fix.x/fix.scale, 1.0*fix.y/fix.scale);
}

不同类型间的转换需要cast,否则编译时会被警告。后门还是有的,就是void *类型。我们声明id是此void *类型,加入一个使用它的迷你函数:

typedef void *id;

id thePoint(id thePoint) {
    return thePoint;
}

这样在main里我们可以使用明确的类型转换,不会被警告:

id flid = thePoint(&flo);
printf("(%f,%f)\n", ((FloatingPoint *)flid)->x, ((FloatingPoint *)flid)->y);

但类型错了也没了警示报告:

FloatingPoint *flip = thePoint(&fix);
printf("(%f,%f)\n", flip->x, flip->y);

我们试着改写为间接的函数指针类型,当然也没有编译预警:

id (*thePointPointer)(id);
thePointPointer = &thePoint;

flip = thePointPointer(&fix);
printf("(%f,%f)\n", flip->x, flip->y);

但如果我们加入明确类型,就会看到预期的警示,虽然是有些啰嗦:

FloatingPoint *(*theFloatingPointPointer)(FloatingPoint *);
theFloatingPointPointer = &thePoint;

flip = theFloatingPointPointer(&fix);
printf("(%f,%f)\n", flip->x, flip->y);

但这很容易解决,写在一行就行了:

FloatingPoint *flop = ((FloatingPoint *(*)(FloatingPoint *))&thePoint)(&fix);

我想这就是书中提到的意思。Objective-C是超级的C语言,这些馄饨都被精心的包装成了简洁的语法。带类型检查的动态语言 —— 我喜欢。