strdup():对警告信息困惑('implicit declaration'、'makes pointer...without a cast'、内存泄漏)

21
当我编译下面这段简短的代码(我们定义一个字符串,然后使用strdup进行复制),我收到了3个警告:2个来自GCC编译器的警告和1个由valgrind报告的运行时警告/错误。
我怀疑内存泄露错误(由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)

您没有包含 strdup 相关的头文件。 - Oliver Charlesworth
2
他做了。@OliverCharlesworth - alk
4个回答

42
C标准库没有strdup函数,但通常在标准库实现中提供此流行函数作为扩展。在GCC实现中,该函数声明在<string.h>中,您需要包含它。
然而,当使用更严格的标准设置(如-std=c99)编译代码时,编译器会隐藏标准库头文件中的非标准函数声明。这就是在您的情况下发生的strdup声明被警告的典型警告。从C99的角度来看,这是一个错误,但您的编译器认为警告已经足够了。如果从编译器的命令行中删除-std=c99开关,strdup的声明将变得可见,并且代码将编译而无需出现该警告。
更技术地说,通过命令行指定-std=c99会使GCC定义__STRICT_ANSI__宏,从而导致所有非ANSI函数声明从标准头文件中“消失”。
该函数仍然存在于库中,这就是为什么您的代码可以正确链接的原因。请注意,它不一定会正确运行,因为编译器假定strdup返回一个int,而实际上它返回一个指针。
valgrind报告只是内存泄漏的结果。strdup分配内存,您应该在不再需要它时自行释放内存。

3
尽管strdup()<string.h>中声明,但它并不是标准的C语言库函数。抱歉,我刚开始解析那个句子时有些困难。 - WhozCraig
2
“真正”的参考资料:http://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html @WhozCraig - alk
@alk 是的,我只是找到了第一个规定该函数标准的链接(它在里面,你的链接指向了标准规范。谢谢)。 - WhozCraig
你做得很好 - 我进行了更改,它运行得非常顺利。关于“-std=c99”标志:我包含它是为了使用c99语法,例如,for(int i = 0, i < n; ++i)。有没有办法让我两全其美?还是解决方案只是包含标志并忽略编译器发出的这些类型的警告? - iceman
1
@Dipak C: -std=gnu99将为您提供最佳的解决方案。 - AnT stands with Russia
显示剩余2条评论

15

strdup()不是标准的C函数,它是POSIX扩展

为了在严格遵守C99标准的情况下,在使用-std=c99选项时使strdup()可用,您需要#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

那个最后的“200909L”是错误的,对吗?我猜应该是“200809L”。 - hmijail
@hmijail 当然可以!感谢您的通知。问题已经修复。 - alk

1
如AnT所说,当您使用标志“-std=c99”时,编译器会隐藏头文件“string.h”中的所有非标准函数。
一种解决方法是在代码开头(或任何您想要的地方,只要在使用strdup函数之前)添加以下代码行:
extern char* strdup(const char*);

-3

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

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

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


4
根据原帖提供的来源,<string.h>已经被包含进来了。 - alk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接