中国开发网: 论坛: 程序员情感CBD: 贴子 355279
haitao
应聘Linux C程序员中的strcpy()函数
应聘Linux C程序员中的strcpy()函数

http://blog.csdn.net/dimensioll/archive/2006/07/04/876071.aspx

很多公司用这个函数考察应聘者的一些技能,如代码风格、代码成熟度等。
首先要避免国内一些教科书的误导的诸如while(*dest++=*src++)这样的代码。
我把参考写法如下(纯C代码):
-----------------------------------------------------------------------------
000
001 # include <stddef.h>
002
003 # define BOUNDS_VIOLATED (__builtin_trap (), 0)
004
005 # define CHECK_BOUNDS_LOW(ARG) \
006 (((__ptrvalue (ARG) < __ptrlow (ARG)) && BOUNDS_VIOLATED), \
007 __ptrvalue (ARG))
008
009 # define CHECK_BOUNDS_HIGH(ARG) \
010 (((__ptrvalue (ARG) > __ptrhigh (ARG)) && BOUNDS_VIOLATED), \
011 __ptrvalue (ARG))
012
013 /* copy src to dest */
014 char *
015 strcpy ( char *dest, const char *src)
016 {
017 register char c;
018 char *__unbounded s = (char *__unbounded) CHECK_BOUNDS_LOW (src);
019 const ptrdiff_t off = CHECK_BOUNDS_LOW (dest) - s - 1;
020 size_t n;
021 do {
022 c = *s++;
023 s[off] = c;
024 } while (c != '\0');
025 n = s - src;
026 (void) CHECK_BOUNDS_HIGH (src + n);
027 (void) CHECK_BOUNDS_HIGH (dest + n);
028 return dest;
029 }
030
要注意的有:
1、第003行宏调用的函数为指针越界陷阱系统调用(bounds check,即int $5);
2、第006行的‘&&’和‘,’符号在宏中的用法;
3、数据类型的定义,诸如ptrdiff_t, size_t等的使用;
4、第023的s指针为什么高效,如寄存器使用数量是最少的;
5、第026行为什么要返回void类型;
如果你这些都已经很熟悉了,我相信没有公司可以立即拒绝你。
有问题大家探讨,一起学习成长。








Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=876071

[点击此处收藏本文] dimensioll发表于 2006年07月04日 17:47:00


niannian 发表于2006-07-05 09:32:00 IP: 207.46.89.*
char * strcpy(char * dest, const char * src)
{
assert(dest != null && src != null);
char * tmp = dest;
while((*dest++ = *src++) != \0')
;

return tmp;
}

这样可以吗?是不是因为有可能dest指针越界?


国内教科书没有误导 发表于2006-07-05 09:38:00 IP:
国内的人根本就没有作出过高性能而且实用的库而已。
早期的strcpy库确实只有一行代码。
现在抱着奔腾来讥笑古人的代码不严密。



john56 发表于2006-07-05 09:43:00 IP: 219.235.233.*
真没必要,你写个简洁的,我要了,写这么复杂,还真怕要。
这个函数什么都做了。


一凡 发表于2006-07-05 09:59:00 IP:
那个register关键字似乎没有用处,代码会自动优化。
你考虑了这么多,为啥不考虑线程性呢?


TripleX 发表于2006-07-05 10:20:00 IP: 222.128.6.*
from linux kernel source code src/lib/string.c

char *strcpy(char *dest, const char *src)
{
char *tmp = dest;

while ((*dest++ = *src++) != '\0')
/* nothing */;
return tmp;
}


fferror 发表于2006-07-05 10:23:00 IP: 61.187.64.*
请lz或其他高人不吝解释下代码,比如lz提醒注意的第二点,不懂这种用法.


... 发表于2006-07-05 10:28:00 IP: 202.165.107.*
“国内教科书误导”?那个代码好像出自 Kernighan 和 Ritchie 的 The C Programming Language。一个简单的 strcpy 做成这样太复杂了。再说真正的 strcpy 一般是用汇编写的,检查边界这些东西简直是累赘。

另一方面,一个人把一件简单的事做得复杂,不一定说明他能把复杂的事用简单的方式去完成。我更倾向于相信,让这样的人去做复杂的事,反而会做得更复杂。


恋花蝶 发表于2006-07-05 10:33:00 IP: 218.107.55.*
翻了一下楼主的其它文章,发现你说你看过〈UNIX编程艺术〉。我就搞不明白怎么你竟然没有理解 这本书提到的UNIX精神——要相信用户是专业的!C语言的设计就是相信程序员可以自己控制代码,你加上边界检查真是没有必要。


Mr. J 发表于2006-07-05 10:33:00 IP: 211.162.234.*
strcpy本来就存在溢出,要不也不会有个strncpy了,楼主实现有点繁琐


nono 发表于2006-07-05 11:17:00 IP: 219.127.170.*
同意Mr.J, strcpy的局限性二十年前已经有了公论,况且存在补充方案, 没有必要再这样写。


whisper 发表于2006-07-05 11:29:00 IP: 58.207.140.*
keep it simple, stupid


匿名 发表于2006-07-05 11:38:00 IP:
其实是那个出题的人是笨蛋,还自以为自己很高明。
上次华为的人就出了这么个题目给我。
还说我的答案不严谨。


sun_flow 发表于2006-07-05 11:41:00 IP: 211.100.21.*
TrackBack来自《strcpy()函数》:

strcpy()函数


bennipro 发表于2006-07-05 11:54:00 IP: 58.246.225.*
什么乱代码, 在linux gcc 4.1下面编译不过!
严重鄙视之!


bennipro 发表于2006-07-05 12:00:00 IP: 58.246.225.*
在vc6/vs2005下编译也不过, 楼主用的是火星编译器?
还有一个问题, 楼主代码中加入了大量的检测代码, 可是问题是使用C标准库, strcpy(NULL, NULL)必然崩溃, 不知道用楼主的具有超强检测功能的代码会不会崩溃, 如果楼主的代码不会崩溃, 那只能说楼主的代码并不符合C/C++规范, 垃圾也! 如果也崩溃, 那么要那么多的检测代码何用?


john 发表于2006-07-05 12:30:00 IP: 202.205.9.*
总有一些孔乙己, 狗屁不会,就会钻牛角尖。


big name 发表于2006-07-05 12:46:00 IP: 10.50.37.*
楼主写这样的代码体现了不理解软件的层次化和模块化思想


gccr 发表于2006-07-05 12:47:00 IP: 203.86.43.*
无话可说.


dimensioll 发表于2006-07-05 12:51:00 IP: 218.72.97.*
见笑见笑,,,,
事实上你需要会边界检查,但是现在的编译器不支持__bounded 的了。所以我检讨。
但通过预处理,上面的代码就是:
#include <stddef.h>
char *strcpy(char *dest, const char *src)
{
register char c;
const ptrdiff_t off = dest- src - 1;
do {
c = *src++;
src[off] = c;
} while (c != '\0');
return dest;
}

还是有个问题,就是有可能dest==NULL,那此种情况需不需要考虑?





to fferror 发表于2006-07-05 12:59:00 IP: 218.72.97.*
如果支持bounded指针的话:
(((__ptrvalue (ARG) > __ptrhigh (ARG)) && BOUNDS_VIOLATED), __ptrvalue (ARG))
通过((__ptrvalue (ARG) > __ptrhigh (ARG))判断是否越界,如果不越界,通过&&能跳过 BOUNDS_VIOLATED,这是个边界陷阱程序。逗号运算的目的是返回__ptrvalue (ARG)这个值。
while(*dest++ = *src++)这个语句,
我想总是
do{
c = *src++;
src[off]=c;
} while( c !='0');效率高。




罗穆峰 发表于2006-07-05 13:19:00 IP: 202.105.135.*
这是一个库函数,而不是一个软件产品。
库函数是交给程序员使用的,程序员应该知道如何保证参数的安全,而不应该由库函数来做这些事情。
举个更简单的例子:

int * p;
......
*p=8;

编译器将最后一句只是简单地编译为:
mov eax,p
mov [eax],8
假如p指向的是一个不可写的内存地址,将引起内存异常。
我们不能要求编译器为我们生成代码来检查指针是否有效,只能是由程序员来保证指针有效。
同样的,我们不能要求strcpy来为我们处理异常,只能由调用strcpy的人自己保证参数是否有效。



Lemon 发表于2006-07-05 14:11:00 IP: 202.107.200.*
ptrdiff_t 哪里定义的?


使用vc++6.0 编译器
strcpy.obj - 14 error(s), 4 warning(s)

我水平有限 <stddef.h> 是哪个库?

变量命名我看不懂.

就算是需要边界检查 我也可以用10行代码把它写得很漂亮 字符串的拷贝而已 你这个程序我看着很头大 公司里流行这样的程序吗?我看vc++6.0 strcpy() 写得很好啊 .


路人甲 发表于2006-07-06 13:28:00 IP: 210.22.93.*
作者提供的代码和glibc的strcpy.c中的代码一模一样。不知道是谁抄谁的?


肉骨头 发表于2006-07-07 14:09:00 IP: 221.122.38.*
调用频率高的函数,工具函数越简单越好。

有效性检查集中处理,除了问题也能迅速定位。

冗长的Call Stack让人厌烦~~~


也是路人甲 发表于2006-07-07 15:17:00 IP: 221.237.179.*
建议楼主在代码中加上检查指针是否在本模块范围内,是否等于$CCCCCCCC,是否等于$FFFFFFFF,是代码段还是数据段,段是否可写,等等等等~~
我的blog:http://szhaitao.blog.hexun.com & http://www.hoolee.com/user/haitao
--以上均为泛泛之谈--
不尽牛人滚滚来,无边硬伤纷纷现 人在江湖(出来的),哪能不挨刀(总归是要的)
网络对话,歧义纷生;你以为明白了对方的话,其实呢?

您所在的IP暂时不能使用低版本的QQ,请到:http://im.qq.com/下载安装最新版的QQ,感谢您对QQ的支持和使用

相关信息:


欢迎光临本社区,您还没有登录,不能发贴子。请在 这里登录