包含<string.h>仍出现“strtok_r”函数的隐式声明

10
我有以下代码用于将包含以\n分隔的行和每行由\t分隔的整数的字符串进行标记化:
void string_to_int_array(char file_contents[BUFFER_SIZE << 5], int array[200][51]) {
  char *saveptr1, *saveptr2;
  char *str1, *str2;
  char delimiter1[2] = "\n";
  char delimiter2[2] = " ";
  char line[200];
  char integer[200];
  int j;
  for(j = 1, str1 = file_contents; ; j++, str1 = NULL) {
    line = strtok_r(str1, delimiter1, &saveptr1);

    if (line == NULL) {
      break;
    }


    for (str2 = line; ; str2 = NULL) {
      integer = strtok_r(str2, delimiter2, &saveptr2);
      if (integer == NULL) {
        break;
      }
    }
  }
}

这里只包含相关函数,完整的代码如有需要可以在这里查看。

然而,当我尝试使用以下命令编译这段代码时:

gcc -m64 -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes file_read.c

我收到以下警告提示:

file_read.c:49:5: warning: implicit declaration of function ‘strtok_r’ [-Wimplicit-function-declaration]
     line = strtok_r(str1, delimiter1, &saveptr1);
     ^
file_read.c:49:10: error: incompatible types when assigning to type ‘char[200]’ from type ‘int’
     line = strtok_r(str1, delimiter1, &saveptr1);
          ^
file_read.c:59:15: error: incompatible types when assigning to type ‘char[200]’ from type ‘int’
       integer = strtok_r(str2, delimiter2, &saveptr2);
               ^

第49和59行对应strtok_r调用。

你可以看到,在我的文件中包含了string.h(其中声明了strtok_r),但我仍然收到了有关strtok_r的隐式声明警告。

如何消除警告,请提供任何见解。

我在ubuntu 14.04 64位桌面上使用gcc 4.8.2。


3
关于你隐含的声明,strtok_r 应该使用 string.h 正确引入,但它是 POSIX-2001 的特性,你需要确保它被包含。要么在包含任何标准头文件之前加上 #define _POSIX_C_SOURCE 200112L,要么通过编译器命令行开关的 -D 选项提供它。当然,这假设你的实现支持它,并且我当然希望你的实现支持它。 - WhozCraig
@WhozCraig:我在strtok_r的手册页面中没有看到使用#define _POSIX_C_SOURCE,那我怎么知道我应该这样做呢? - jobin
2
请参阅man page中的Feature Test Macro Requirements。我假设您在平台上使用glibc。它可以通过其他方式被引入,其中一些可能会在设置标准开关时默认预定义(例如,-std=c99可能不会打开它,而-std=c11可能会。我没有测试过,但我不会感到惊讶)。 - WhozCraig
@WhozCraig:谢谢!你的评论和nos的答案帮助解决了这个问题。非常感谢! :) - jobin
可能是重复的问题。请检查这个链接 https://dev59.com/sEvSa4cB1Zd3GeqPiOuy 和这个链接 http://stackoverflow.com/questions/19388774/error-implicit-declaration-of-function-strtok-r - CS Pei
@JohnSmith:看起来不是这样,它专门用于内核模块。 - jobin
4个回答

17

strtok_r不是标准的C函数。您使用-std=c99编译器标志只请求了C99标准,因此头文件(glibc的)将只提供string.h中的C99标准函数。

通过使用-std=gnu99启用扩展功能,或者在包含string.h之前定义支持strtok_r的manpage中显示的扩展之一。例如:

#define _GNU_SOURCE
#include <string.h>

请注意,这段代码还存在其他问题:strtok_r返回一个char *,但是你正在尝试将它分配给integer = strtok_r(str2, delimiter2, &saveptr2); 中的字符数组。你的integer变量应该是一个char *


1
谢谢!这是否意味着 strtok_r 降低了可移植性,只能在 Linux 上使用? - jobin
2
是的,这可能会降低可移植性。但是strtok_r是由posix定义的,因此至少几乎所有类unix系统都将拥有它。 - nos
2
@i08in strtok_r 明显降低了可移植性,因为它是一个 *nix 特有的函数,而在 Windows 中则相当于 strtok_s - MDMoore313

3

在Debian上使用GCC 7.4.2时遇到相同的问题。

解决方法:使用__strtok_r-std=gnu99,或在包含头文件后添加函数原型:

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

#define BUFFER_SIZE 1024

extern char *strtok_r(char *, const char *, char **);

1
我使用的是4.8.2和Ubuntu 14.04 64位,但我遇到了不同的错误。
    incompatible types when assigning to type 'char[200]' from type 'char *' 
        line = strtok_r(str1, delimiter1, &saveptr1);
             ^

这里,line声明为'char[200]',但strtok_r返回char*
类似的错误出现在integer = ...的行上。
要消除这些编译错误,您可以声明类似于char *line;的东西。
对于隐式声明的警告,请检查此处 我能在Linux内核模块中使用strtok()吗?

“line”和“integer”以前是“char *”。我改变了它,假设seg错误是因为分配给char指针,但是更改后并没有帮助:您可以尝试将“line”更改为“char *”,而不是“char line [200]”。当您使用我在问题中提到的gcc选项编译它们时,您难道不会收到关于“strtok_r”的隐式声明的警告吗? - jobin
希望你已经使用了我在问题中提到的gcc选项,对吧? - jobin
你为什么跳过了那个?我把它作为我在SO上编译C程序时推荐使用的选项之一包含在我阅读的内容中。 - jobin
谢谢,你提供了很好的见解,但是没有一个答案帮助解决它。 - jobin

1
问题在于函数 strtok_r 返回一个字符指针,你试图将其赋值给一个字符数组,因此为了使其工作,你必须将你的 lineinteger 变量声明为字符指针,然后使用 malloc 分配内存。
void string_to_int_array(char file_contents[BUFFER_SIZE << 5], int array[200][51]) {
  char *saveptr1, *saveptr2;

  char *str1, *str2;

  char delimiter1[2] = "\n";
  char delimiter2[] = " ";
  char *line;
  char *integer;
  int j;
  line = (char*)malloc(200);
  integer = (char*)malloc(200);
  for(j = 1, str1 = file_contents; ; j++, str1 = NULL) {
    line = strtok_r(str1, delimiter1, &saveptr1);
    printf("%s\n", line);
    if (line == NULL) {
      break;
    }
    printf("end of first\n");

    for (str2 = line; ; str2 = NULL) {
    printf("begin of second\n");
      printf("asdf%s\n", line);
      integer = strtok_r(str2, delimiter2, &saveptr2);
      if (integer == NULL) {
        break;
      }
      printf("%s\n", integer);
    }
  }
}

谢谢,那也很有帮助! - jobin

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