strdup()函数
我最近意识到我喜欢在OS X上使用的strdup()
函数不是ANSI C的一部分,而是POSIX的一部分。 我不想重写我的所有代码,所以我想我只是要编写自己的strdup()
函数。 它并不难,真的,它只是一个malloc()
和一个strcpy()
。 无论如何,我有这个function,但是如果我编写这个函数并将它链接到我的代码,我该怎么做,它已经存在于libc中了? 我的链接器或编译器是否允许我基本上定义我自己的函数版本,还是我必须给它另一个名字? 如果有一种方法可以重用相同的名称,那将非常方便,因此如果用户的libc中存在strcpy()
,则可以使用它,但如果它们的libc中不存在,则可以使用我的版本,因为代码变化很小。
简短版本:
a)当我用与内置函数相同的名称编写自己的函数时会发生什么?
b)我可以做些什么来避免在没有strdup()
平台上发生不好的事情而不重写我的所有代码而不使用strdup()
,这有点单调乏味?
通常,您只需使用#if
在某个编译器下定义所需的函数。 如果内置库没有定义strdup,那么自己定义它是没有问题的(除非他们将来定义它,否则你必须把它取出来。)
// Only define strdup for platforms that are missing it.. #if COMPILER_XYZ || COMPILER_ABC char *strdup(const char *) { // .... } #endif
您可以使用这样的宏,这样您可以使用旧名称,但链接器将看到不同的名称;
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)
正如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等? 同样的工作。 通过在您的构建脚本中进行测试,它可以在没有任何额外工作的情
a)当我用与内置函数相同的名称编写自己的函数时会发生什么?
您无法重新定义已包含的头文件中已存在的函数。 这将导致编译错误。
b)我可以做些什么来避免在没有strdup()的平台上发生不好的事情而不重写我的所有代码而不使用strdup(),这有点单调乏味?
我建议创建自己的包装函数来进行strdup,并替换所有调用以使用新的包装函数。 例如:
char *StringDuplicate(const char *s1) { #ifdef POSIX return strdup(s1); #else /* Insert your own code here */ #endif }
将所有调用从strdup更改为StringDuplicate()应该是一个简单的查找和替换操作,使其成为一种可行的方法。 然后,特定于平台的逻辑将保存在单个位置,而不是分散在整个代码库中。
您还应该考虑避免创建以str [az]开头的任何标识符(包括函数)。 虽然这不是保留的,但C标准(ISO / IEC 9899:1999)第7.26.11节(未来的库指示)声明“以str,mem或wcs开头的函数名称和小写字母可以添加到声明中在标题中。“
仅供参考:我从未亲眼见过没有定义strdup()的环境。
如果有人读到这个:即使可用,也不要使用平台的strdup(),并且不要浪费时间/精力使用autoconf / automake来使用它。 说真的,这有多难:
char* mystrdup(const char* str) { return strcpy(malloc( strlen(str) + 1),str); }
这真的值得#ifdefs吗? 编译检查? 吻