Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1715981
  • 博文数量: 177
  • 博客积分: 9416
  • 博客等级: 中将
  • 技术积分: 2513
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-06 16:08
文章分类

全部博文(177)

文章存档

2013年(4)

2012年(13)

2011年(9)

2010年(71)

2009年(12)

2008年(11)

2007年(32)

2006年(25)

分类: C/C++

2007-09-24 20:26:57

今天在CSDN上真的看见了孔乙己式的问题:用C语言,不用四则运算,对一个变量进行加1操作。答案是(i在某处定义了):
i = (int)&(((char*)i)[1]);

想出这个问题的兄台真是够孔乙己的——除了用+、-、*、/和++,还有别的方法对一个变量加1——茴香豆的“茴”字有六种写法……据说这是一道笔试题。sigh……有钻研精神,可是没有实用主义。
 
在这里解释一下为什么能够实现对i加1,以免有些初学者不懂,另一个目的也是希望大家引以为戒,不要这么孔乙己(关于指针的问题,可以参考我的文章“指针是通往地狱的捷径”):
 
首先,看最里面两层括号:
((char*)i)
 
这里将i从整型转换成一个ulong,并使之成为一个指向字符(字符串)的指针,记为ptr。然后是:
i = (int)&(ptr[1]);
 
这就是说,将ptr作为一个指向字符串的指针,这里ptr[1]就相当于*(ptr + 1),因为数组名其实就是地址,所以ptr[1]与*(ptr + 1)等价(有疑问的请参考“The C Programming Language, by Kernigham & Ritchie”)。比如:
 
/* C代码 */
char a[] = "hello, world";
char * ptr = a;
 
printf("%c, %c, %c, %c\n", *(ptr+4), ptr[4], a[4], *(a+4));
 
输出的结果将是:o, o, o, o
 
好了,既然ptr[1]等价于ptr + 1,那么整个表达式可以写成:
int i = (int)(ptr + 1);
 
由于char *所指向的是字符,只占用一个字节,那么指针算术ptr+1将导致ptr的ulong值加1,这样就相当于:
int i = int((ulong)i + 1);
 
这里有这些知识点:指针、数组、指针算术、强制类型转换。看起来出题人对这些知识点的了解还是比较深刻。可我必须说:真是孔乙己式的问题!这点稍微有点深刻的理解只不过为了炫耀而已!这种人能出面试题,且被该公司采用,简直就是中国IT人的耻辱,希望以后这位老兄不要说他是干IT的,咱丢不起那人!自作聪明的家伙!这就跟为了放屁就脱了裤子坐在马桶上,拿本书,然后放个屁走人是一个道理。只可惜,他还崩了一屁股水。
 
这种解答很有技巧性,也说明该老兄脑子里的筋很多,很多弯——去忽悠赵本山都绰绰有余,可是他不像搞IT的,更像是本山大叔,出的题也像“茴字有六种写法你知道吗?”和“1加1在什么情况下等于3?”,三者如出一辙。建议这位老兄搞点好本子,上春晚忽悠去,那里还有人捧场,还能逗乐子。
 
为什么说他崩了自己一屁股水:
1、这条语句的效率问题。要实现对一个变量加1,写成:
i + 1;
或者++i;
翻译成汇编代码基本就是:
ADD i, 1
而且这是单条指令的运算,用ALU就能完成,效率多高!再看看答案,两次强制类型转换,一个指针算术,最后一个赋值,翻译成汇编代码,不知道要多少条(与编译器有关)!效率当然低下!
 
2、溢出问题导致的错误。假如i的值正好是最大的有符号整数(假设int只有16位,那就是65535),将其转换成ulong,值不会变。然后加1,再转换成int,然后,你的答案就是绝对错误的,溢出了!不光如此,加入碰到大小端问题,情况就会变得更复杂。
 
3、安全问题。对于内存的访问,指针是罪恶之源,这也是C#/JAVA等语言摒弃了指针的原因(当然C#提供了managed pointer),无论什么时候,对于指针操作都要万分小心。这道题里用了这么多转换,目的无非就是把人绕晕,对于安全性根本没有概念。
 
出这道题的老兄,省省劲吧。要是我笔试or面试碰上这样的题,我绝对会鄙视他一番,然后问他:“茴香豆的茴字有六种写法,你会么?”问完之后,扬长而去——为出这种题的公司干活,不丢人么?
 
说实在的我也挺无聊,闲着没事跟孔乙己叫什么真?看来真得约上这位出题的老兄去后海边的孔乙己酒吧喝点酒,看他排出九文大钱,用手指蘸着酒在桌上画着,再听他拽一遍:“茴香豆的茴字有六种写法,你会么?”
 
Copyleft (C) 2007-2009 raof01.
本文可以用于除商业外的所有用途。此处“用途”包括(但不限于)拷贝/翻译(部分或全部),不包括根据本文描述来产生代码及思想。若用于非商业,请保留此 权利声明,并标明文章原始地址和作者信息;若要用于商业,请与作者联系(raof01@gmail.com),否则作者将使用法律来保证权利。
 
阅读(6055) | 评论(23) | 转发(0) |
给主人留下些什么吧!~~

dorainm2008-01-19 13:46:12

i = (int)&(((char*)i)[1]); - -! 果然呐, 从C语言上理解,把 i的值当作指针地址去寻值*,然后把那地址当作数组首地址,用[1]偏移量去寻找 1*sizeof(char)的值,(这样子读取到的地址,就是i指定的地址+1的位置了),然后再&取址,最后强制转换回(int),赋值给i,i就自然得到一个比原先+1的值