4

我用 C 编写程序。我读到了这个strdup()函数。据我所知,该strdup()函数分配空间而strcpy()没有分配空间。但问题strdup()是它分配空间但不释放它。strdupa()分配和释放空间。但是在某些地方,我读到该strdupa()功能很危险。如果有人能告诉我为什么strdupa()危险,那将很有帮助。此外,当我尝试在我的 Open Suse 12.1 32 位系统中运行程序时,gcc给出了一个错误,提示strdupa()不存在。如果strdupa()是一个危险的功能,有人可以告诉我strdupa()使用该功能时要使用的副本和标题。

4

1 回答 1

12

strdupa()函数被记录为使用该alloca()函数来分配内存。这意味着它的内存在函数返回时被释放。该alloca()功能不是特别可移植的;该strdupa()功能同样不是那么便携。

手册页记录了该strdupa()功能仅在您编译时可用-D_GNU_SOURCE,或者如果您使用gcc -std=gnu11或类似的东西。

如果在调用的函数strdupa()返回后需要访问内存,那么就不能使用strdupa()-strdup()是必要的。如果您担心可移植性,您可能会使用strdup(),尽管它仅由 POSIX ( strdup()) 而非标准 C 定义。请注意,这strdup()TR 24731-2: Extensions to the C Library - Part II: Dynamic allocation functions 的一部分. AFAIK,alloca()既不是 POSIX 的一部分,也不是标准 C 库的提议扩展的一部分。


使用“strdupa()”有什么危险吗?

这取决于你对“危险”的定义。是的。如果堆栈上没有足够的空间存放字符串,那么当不会strdupa()时会失败strdup()。有些人不喜欢,alloca()因此他们不热衷于使用alloca(). 手册页有大量关于问题的alloca()注释,其中一个是您无法判断何时alloca()失败。

是否有检查alloca()故障的工具——例如valgrind内存泄漏?

您寻找核心转储;如果程序崩溃,可能是因为alloca()分配失败。使用valgrind可能会发现问题;但是,您仍然无法可靠地从问题中恢复,并且您的生产代码可能不会valgrind在 . 如果您想要可靠的行为,请使用strdup()- 并接受您需要手动释放分配的内存。

从手册页alloca()

注意
alloca()函数依赖于机器和编译器。对于某些应用程序,与使用 malloc(3) 和 free(3) 相比,使用它可以提高效率。在某些情况下,它还可以简化使用 longjmp(3) 或 siglongjmp(3) 的应用程序中的内存释放。否则,不鼓励使用它。

因为分配的空间alloca()是在堆栈帧中分配的,所以如果函数返回被调用 longjmp(3) 或 siglongjmp(3) 跳过,则该空间会自动释放。

不要试图释放 (3) alloca() 分配的空间!

GNU 版本注意事项
通常,gcc(1) 将调用转换alloca()为内联代码。当给出-ansi, -std=c89, -std=c99, 或选项时(并且不包括-fno-builtin标题),这不会完成。<alloca.h>但要小心!默认情况下,glibc 版本的<stdlib.h>include<alloca.h>包含以下行:

#define alloca(size)   __builtin_alloca (size)

如果有人拥有此功能的私有版本,则会产生混乱的后果。

代码被内联的事实意味着不可能获取这个函数的地址,或者通过链接不同的库来改变它的行为。

内联代码通常由一条调整堆栈指针的指令组成,并且不检查堆栈溢出。因此,没有 NULL 错误返回。

错误
如果堆栈帧无法扩展,则没有错误指示。(但是,在分配失败后,如果程序尝试访问未分配的空间,它很可能会收到 SIGSEGV 信号。)

在许多系统alloca()上不能在函数调用的参数列表中使用,因为保留的堆栈空间alloca()将出现在函数参数空间中间的堆栈上。

于 2015-11-16T03:18:41.100 回答