17

当我编译下面的一小段代码时(我们在其中定义了一个字符串,然后使用 strdup 进行复制),我收到 3 个警告:来自 GCC 的 2 个编译器警告和来自 valgrind 的 1 个运行时警告/错误。

我怀疑内存泄漏错误(由 valgrind 报告)也与我对 strdup 的使用有关,这就是我在下面包含相关输出的原因。

我究竟做错了什么?(我正在阅读一本 C 书,这就是作者使用 strdup 的方式。)


编码:

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
  char *string1 = "I love lamp";
  char *string2;

  string2 = strdup(string1);

  printf("Here's string 1: %s\n"
     "Here's string 2: %s\n",
     string1, string2);

  return 0;
}

警告/输出:

dchaudh@dchaudhUbuntu:~/workspaceC/LearnCHW/Ex17_StructsPointers$ make test
cc -std=c99    test.c   -o test
test.c: In function ‘main’:
test.c:9:3: warning: implicit declaration of function ‘strdup’ [-Wimplicit-function-declaration]
   string2 = strdup(string1);
   ^
test.c:9:11: warning: assignment makes pointer from integer without a cast [enabled by default]
   string2 = strdup(string1);
           ^
dchaudh@dchaudhUbuntu:~/workspaceC/LearnCHW/Ex17_StructsPointers$ valgrind --track-origins=yes --leak-check=full ./test
==3122== Memcheck, a memory error detector
==3122== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==3122== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==3122== Command: ./test
==3122== 
Here's string 1: I love lamp
Here's string 2: I love lamp
==3122== 
==3122== HEAP SUMMARY:
==3122==     in use at exit: 12 bytes in 1 blocks
==3122==   total heap usage: 1 allocs, 0 frees, 12 bytes allocated
==3122== 
==3122== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3122==    at 0x4C2ABBD: malloc (vg_replace_malloc.c:296)
==3122==    by 0x4EBF2B9: strdup (strdup.c:42)
==3122==    by 0x4005A4: main (in /home/dchaudh/workspaceC/LearnCHW/Ex17_StructsPointers/test)
==3122== 
==3122== LEAK SUMMARY:
==3122==    definitely lost: 12 bytes in 1 blocks
==3122==    indirectly lost: 0 bytes in 0 blocks
==3122==      possibly lost: 0 bytes in 0 blocks
==3122==    still reachable: 0 bytes in 0 blocks
==3122==         suppressed: 0 bytes in 0 blocks
==3122== 
==3122== For counts of detected and suppressed errors, rerun with: -v
==3122== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
4

4 回答 4

35

C 标准库没有strdup. 然而,这个流行的功能通常由标准库实现作为扩展提供。在 GCC 实现中,此函数在 中声明<string.h>,您确实包括在内。

但是,当您使用更严格的标准设置(例如 )编译代码时,-std=c99编译器会隐藏标准库头文件中的非标准函数声明。这就是strdup您的情况下发生的声明。您收到的警告是当您尝试调用未声明的函数时发出的典型警告。从形式上看,从 C99 的角度来看,这是一个错误,但您的编译器认为在这种情况下发出警告就足够了。如果您-std=c99从编译器的命令行中删除该开关,则 的声明strdup将变得可见,并且代码将在没有警告的情况下编译。

从技术上讲,-std=c99在命令行中指定会使 GCC 定义__STRICT_ANSI__宏,这会导致所有非 ANSI 函数声明从标准头文件中“消失”。

该函数仍然存在于库中,这就是您的代码正确链接的原因。请注意,它不一定能正常运行,因为编译器假定strdup返回了一个int,而实际上它返回的是一个指针。

valgrind 报告只是内存泄漏的结果。当您不再需要它时strdup,分配您应该给自己的内存。free

于 2014-10-09T17:10:16.017 回答
12

strdup() 不是标准 C。它是 POSIX 扩展

strdup()在使用该选项时即使严格遵守 C99 合规性也可以使用,您至少-std=c99需要以下一项:#define

_SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 
  || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
  || /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L

(取自strdup()的 Linux 手册页

例如通过编码(包括之前<string.h>):

#define _SVID_SOURCE

或者:

#define _POSIX_C_SOURCE 200809L

或者,您可以通过 GCC 的命令行将这些定义作为选项传递

-D_SVID_SOURCE

或者

-D_POSIX_C_SOURCE=200809L
于 2014-10-09T18:28:53.733 回答
1

正如 AnT 已经说过的,当您使用标志“-std=c99”时,编译器会在头文件“string.h”中隐藏所有非标准函数

修复它的一种方法是在代码的开头添加这行代码(或任何你想要的地方,只要它在使用 strdup 函数之前)

extern char* strdup(const char*);

于 2019-11-24T21:49:41.203 回答
-3

您的编译器没有声明 strdup,因为您没有 #include 任何声明它的头文件。

由于没有声明,编译器猜测 strdup 将返回一个 int。您将调用 strdup 的结果分配给指针变量。

包含正确的头文件,您的问题至少应该减少。

于 2014-10-09T17:10:42.417 回答