2009-01-27 77 views
15

我最近才意识到我在OS X上使用如此多的函数的strdup()函数不是ANSI C的一部分,而是POSIX的一部分。我不想重写我所有的代码,所以我想我只是写我自己的strdup()函数。这并不难,真的,这只是一个malloc()strcpy()。无论如何,我有这个函数,但是如果我编写这个函数并将其链接到我的代码,并且它已经存在于libc中,我该怎么办?我的链接器或编译器是否允许我基本定义自己的函数版本,还是必须给它另一个名称?如果有一种重用相同名称的方法,这非常方便,因此如果strcpy()存在于用户的libc中,他们可以使用它,但是如果它不存在于libc中,他们可以使用我的版本,代码更改尽可能。strdup()函数

短的版本:

一)当我写我自己的函数具有相同的名称作为一个内置的功能,会发生什么?

B)我能做些什么,以避免不好的事情发生在我的平台上没有strdup()无需重写我的代码,不使用strdup(),这仅仅是一个有点乏味?

回答

20

通常,您只需使用#if来定义在特定编译器下所需的函数。如果内置库没有定义的strdup,有自己定义它(除如果他们在将来定义它,你必须把它取出来。)没问题

// Only define strdup for platforms that are missing it.. 
#if COMPILER_XYZ || COMPILER_ABC 
char *strdup(const char *) 
{ 
    // .... 
} 
#endif 
+8

如果您觉得雄心勃勃,您甚至可以设置automake和autoconf来配置测试是否需要自己定义strdup所需的宏,而不是列举您希望支持的所有编译器和环境。 – 2009-01-27 06:28:24

4

a)当我编写自己的 函数时,会发生什么情况,它的内置函数名称与 相同?

您不能重新定义您正在包含的头文件中已存在的函数。这将导致编译错误。

B)我能做些什么,以避免不好的事情 发生在我身上对 没有的strdup平台()而无需重写 我所有的代码不使用的strdup(),它 只是有点乏味?

我会建议创建自己的包装函数到的strdup,并更换所有通话使用新的包装函数。例如:

char *StringDuplicate(const char *s1) 
{ 
#ifdef POSIX 
    return strdup(s1); 
#else 
    /* Insert your own code here */ 
#endif 
} 

改变从的strdup到StringDuplicate所有电话()应该是一个简单的查找和替换操作,使其成为一个可行的办法。特定于平台的逻辑将保存在一个单独的位置,而不是散布在整个代码库中。

2

仅供参考:我从未见过没有定义strdup()的环境。

+1

我过去也喜欢strdup - 直到我告诉那个在irc.freenode.org上## c的人。他们不喜欢它,并认为如果有两条简单线条,保证工作方式 - 为什么要依靠不可移植的功能? (strdup在Windows中已弃用,而win ce似乎没有) – 2009-01-27 05:47:44

+0

msdn表示应该使用_strdup来代替。但我认为我阅读这些弃用警告无论如何都是无稽之谈:)但今天看到strdup实际上被广泛使用,这让我感到惊讶。 – 2009-01-27 05:49:39

6

你可以使用像这样的宏,这样你可以使用旧名称,但链接器会看到不同的名称;

char *my_strdup(const char *s) { 
    char *p = malloc(strlen(s) + 1); 
    if(p) { strcpy(p, s); } 
    return p; 
} 

/* this goes in whatever header defines my_strdup */ 
char *my_strdup(const char *s); 
#define strdup(x) my_strdup(x) 
+0

很好的解决方案,但是你需要在其他一些检查机制中包装strdup(x)的#define来确定它是否需要被替换。如果没有,你可能想使用libc strdup – Matt 2009-08-12 18:54:19

3

您还应该考虑避免创建以str [a-z]开头的任何标识符(包括函数)。虽然这不是保留,但C标准(ISO/IEC 9899:1999)第7.26节。11(未来的图书馆方向)指出:“以str,mem或wcs开头的函数名称和小写字母可能会添加到标题中的声明中。”

6

正如Rob Kennedy指出的,如果这个函数存在或不存在,最好的方法是在你的构建脚本里面测试。我知道使用autoconfig这个过程相当简单,但也可能使用其他跨平台构建脚本工具。

然后你只需将你的头文件:


#ifndef HAVE_STRDUP 
# ifdef HAVE__STRDUP 
# define strdup _strdup 
# else 
# define strdup my_strdup 
# endif 
#endif 

的strdup如果在目标平台上已经存在的libc的版本使用,如果没有你的自定义功能my_strdup将使用。

编辑:我应该添加一个为什么它更好的探索。

首先,编译器与libc中函数的存在无关。例如采取功能strlcpy。它存在于FreeBSD上,但不在Linux(glibc)上,尽管它们默认都使用gcc。或者如果有人打算用clang编译你的代码会发生什么?

第二个平台检查(我不知道是否有一个标准方法)只有在你明确地为每个平台添加你想要支持正确的预处理器条件时才能工作。所以假设你已经掌握了在OSX和Win32上编译你的应用程序,并且你现在想在Linux上编译它,你必须通过所有的预处理器条件才能看到它们是否适用于Linux。也许你还想支持FreeBSD,OpenBSD等?同样的工作。通过在构建脚本中进行测试,它可以在没有任何额外工作的情况下编译。

-2

如果其他人读到这样的话:即使可用,也不要使用平台的strdup(),并且不要浪费时间/精力用autoconf/automake来使用它。认真地说,这是多么困难:

char* mystrdup(const char* str) 
{ 
return strcpy(malloc(strlen(str) + 1),str); 
} 

这是否真的保证#ifdefs?编译器检查?吻。