Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1714569
  • 博文数量: 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),否则作者将使用法律来保证权利。
 
阅读(6049) | 评论(23) | 转发(0) |
给主人留下些什么吧!~~

kinfinger2011-05-06 19:36:53

受教 了,初出茅庐,

liseyy2011-03-11 15:55:20

个人有个人的想法而已。这只是面试题而已,至少锻炼一下思维。C语言本来就博大精深。。。

chinaunix网友2008-09-08 16:30:57

无意中看到这篇文章,看到这个题目,挺有意思的.分析了一下. 觉得主要的问题就是可能会访问到超过4G之外的内存.这个问题是存在的. 但文中似乎并没有对相应的内存地址进行斌值,所以不至于安全危险吧.?

chinaunix网友2008-02-22 20:29:45

我是真的不想去他们公司——“出这道题的老兄,省省劲吧。要是我笔试or面试碰上这样的题,我绝对会鄙视他一番,然后问他:“茴香豆的茴字有六种写法,你会么?”问完之后,扬长而去——为出这种题的公司干活,不丢人么?”。 打算跟猎头说说,让他别再在我身上费心了,影响他的业绩啊。

chinaunix网友2008-02-22 20:24:23

被猎头推荐去某国际知名的手机游戏公司(世界前十)的中国研发中心笔试,其中就有一道类似的题: 已知char * ptr = "Hello, world!";则 *(char*)(((int*)(&ptr[1])+1));的结果是什么? 这题跟楼主说的基本上一样,非常恶心(答案是',')。真不知道这么知名的公司怎么会出这样的题……另外,这个职位要求技能是C++,但整套题只有一道与C++相关,还是C++不倡导的东西:类型转换。原题是:C++的类型转换有哪些方法。且不说别的,若真是C++题,上面说的那个字符串问题就不会这么出了——至少用const修饰一下*ptr啊! 上面那道字符串的题,以及这道题:求a++%++b*c的值,都违背了软件工程思想。只有两道题我觉得有点水准(一道是给定两个圆的圆心坐标及直径,求这俩圆是否相交,并作优化;另一道是问两个指针相加或相减有何后果),其他的就太令我跌破眼镜了。 整套题里面没有任何关于C++精髓的东西——虚拟、继承、类型系统——这也能叫C++试题(如试题的标题所示)? 说句实话,答了几题我就想走了——无奈会对猎头有影响,毕竟不能因为自己害了别人。