15

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

简短版本:

a) 当我编写自己的函数与内置函数同名时会发生什么?

strdup()b) 我能做些什么来避免在没有将我所有的代码重写为 not use的平台上发生不好的事情strdup(),这有点乏味?

4

7 回答 7

20

通常,您只需#if在某个编译器下使用 an 来定义您想要的功能。如果内置库没有定义strdup,那么自己定义也没问题(除非他们以后定义了,你得把它拿出来。)

// Only define strdup for platforms that are missing it..
#if COMPILER_XYZ || COMPILER_ABC
char *strdup(const char *)
{
   // ....
}
#endif
于 2009-01-27T05:19:56.807 回答
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)
于 2009-01-27T05:52:26.570 回答
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 等?同样的工作。通过在您的构建脚本中进行测试,它可以在没有任何额外工作的情况下编译。

于 2009-01-27T08:30:52.930 回答
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() 应该是一个简单的查找和替换操作,使其成为一种可行的方法。然后,特定于平台的逻辑将保存在一个位置,而不是分散在整个代码库中。

于 2009-01-27T05:23:50.263 回答
3

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

于 2009-01-27T07:19:40.060 回答
2

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

于 2009-01-27T05:39:06.457 回答
-3

如果其他人读到此:即使可用,也不要使用平台的 strdup(),也不要为了使用它而在 autoconf/automake 上浪费时间/精力。说真的,这有多难:

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

这真的保证#ifdefs 吗?编译器检查?吻

于 2010-07-13T11:12:11.767 回答