要求:写一个最短的,能通过编译的C语言程序,但不要求能正确运行。
一般人首先想到的是除0。即
int main()
{
return /;
}
除0会引发SIGFPE信号(浮点异常)。
我们也可以删掉return,但是这样做的话编译器会把这句没有值的语句优化掉。那么我们就改成赋值语句:
i;
int main()
{
i = /;
}
在C89标准里,声明一个整形变量可以省略int。因此我们还可以把main函数的int类型声明也省略掉,变成
i;
main()
{
i = /;
}
不计任何空格,这段程序只有16个字符,可以说是非常短了。但是,我们还可以进一步缩短它。
当C程序在编译的时候,编译器会产生一个或更多对象文件,文件里有对于用到的库和全程对象(函数和变量)的符号索引。然后这些对象文件会进行链接,这是符号索引被地址所代替,就产生了一个可执行文件。
编译器在一个对象文件里提供了一个调用main函数的入口点。调用main函数,意味着我们试图执行存储在main函数链接的位置所对应的地址里的指令。
有趣的是,链接器对于不同对象的类型是没有概念的,它只知道它们的地址。所以,如果我们用一个常规的全程变量替换main函数,编译器会高兴地build对象文件,因为它不关心main的类型是什么;链接器也会高兴地链接它,因为它只关心main函数对应的地址。
所以,考虑这个C程序:
int main=;
这个程序会试图按函数的方式去执行main,但是这样不会奏效,因为编译器把它放到了不可访问的地址上,所以变量main实际上可以初始化为任何值。
继续省略int类型声明,我们得到:
main=;
而事实上,main在这里是个全局变量,而C语言中的全局变量都会隐式地初始化为0,因此上述语句就等价于
main;
好了,这个程序可以编译通过!虽然执行的时候一定会触发SIGSEGV信号,产生Segment fault。但这已经满足了我们一开始给出的要求了(能编译通过但不一定正确运行的最短C语言程序)。