puzzle 9:
#include <stdio.h> int main(void) { int i; i = 10; printf("i: %d\n", i); printf("sizeof(i++) is: %d\n", sizeof(i++)); printf("i: %d\n", i);
return 0; } |
输出为10,4,10:
sizeof是一个运算符,在编译时便已经确定好数值了。i++类型为整数类型,大小为4,i++本身不会进行运算。
puzzle 10:
Write a C program prints "Hello World" without using a semicolon. |
方法一:利用if () {}语句,在条件表达式中书写printf函数;
方法二:利用while () {}语句,在条件表达式中书写printf函数。
puzzle 11:
#include <stdio.h> int main() { int a = 3, b = 5; printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]); printf(&a["WHAT%c%c%c %c%c %c !\n"], 1["this"], 2["beauty"], 0["tool"], 0["is"], 3["sensitive"], 4["CCCCCC"]); return 0; } |
输出为:
Hello! how is this? super
That is C !
输出看上去很奇怪,仔细分析一下。C语言中a[1]和1[a]的写法是等价的,所以这里我们可以将源程序改写一下,例如(&("junk/super"))[b],表示取字符常量中的子字符串,为"super",其它可以类似推导。
puzzle12:
void change() //function should always give 5.you can't change the main function |
怎么去做这个事情呢,方法有很多,这里列举三个:
前两个可以说是聪明的做法
{ printf("%d\n", 5); exit(0); }
{ #define printf_ printf
#define printf(a, b) printf_("5");}
最后一个做法相比就比较专业,其原理是找到程序的代码段(页面分配),然后使得页面可写,找到main中的字符串10,将其修改为5,这样就达到目的了。
/* Linux下可行,使用sysconf获取页面大小,然后使用一个地址指针指向main函数,然后修改代码,将页面变为只读属性 */
void _change() /* 还原操作 */ |
这样的原理是不是很有趣?
总结:
C语言的puzzle主要是区分一些平时似是而非的地方,这与C语言的标准和灵活特性是分不开的。如果不希望自己的程序被别人读懂且能够使用一些hack技术,那么你写的代码一样是puzzle。