【问题标题】:Implicit Declaration of Function ‘strtok_r’ Despite Including <string.h>尽管包含 <string.h> 函数“strtok_r”的隐式声明
【发布时间】:2014-07-20 14:24:18
【问题描述】:

我有以下代码来标记包含由\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;
      }
    }
  }
}

(这里只包含了相关功能,完整的,如果需要的话,是here。)

但是,当我尝试使用以下代码编译此代码时:

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。

【问题讨论】:

  • 关于你的隐式声明,strtok_r 应该使用string.h 正确引入,但它是 POSIX-2001 特性,你应该确保它被包含在内。 #define _POSIX_C_SOURCE 200112L 在包含任何标准头文件之前,或者通过编译器的命令行开关上的 -D 选项提供它。当然,假设您的实现支持它,我当然希望您的实现支持它。
  • @WhozCraig:我在strtok_r 的手册页中没有看到使用#define _POSIX_C_SOURCE ,我怎么知道我应该这样做?
  • 查看man page 中的功能测试宏要求。我假设你在你的平台上使用 glibc。还有其他方法可以吸收它,其中一些可能是在您设置标准开关时默认预定义的(例如,-std=c99 可能不会打开它,而 -std=c11 可能会。have' t 测试过,但我不会感到惊讶)。
  • @WhozCraig:谢谢!您的评论以及 nos 的回答有助于解决这个问题。非常感谢! :)

标签: c string tokenize strtok gcc-warning


【解决方案1】:

我也在使用 4.8.2 和 ubuntu 14.04 64bit。但我得到了不同的错误。

    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; 的内容。

有关隐式声明的警告,请查看此

Can I use strtok() in a Linux Kernel Module?

【讨论】:

  • lineinteger 以前是 char *s。我已经改变了假设段错误是因为分配给 char 指针,但改变没有帮助:您可以尝试将 line 更改为 char* 而不是 char line[200]。当您使用我在问题中提到的 gcc 选项编译 strtok_r 的隐式声明时,您不会收到警告吗?
  • 我希望你已经使用了我在问题中提到的 gcc 选项,不是吗?
  • 您有什么理由跳过它?我把它作为我读过的推荐选项的一部分,在 SO 上编译 C 程序时应该使用。
  • 谢谢,您对原因提供了深刻的见解,但没有回答帮助解决了问题。
【解决方案2】:

strtok_r 不是标准的 C 函数。您通过使用 -std=c99compiler 标志仅要求 C99,因此(glibc 的)头文件只会使您可以使用 string.h 中的标准 C99 函数。

通过使用 -std=gnu99 或定义其中一个扩展来启用扩展,如 strtok 的联机帮助页中所示,它在包含 string.h 之前支持 strtok_r。例如

#define _GNU_SOURCE
#include <string.h>

请注意,代码还有其他问题,strtok_r 返回一个 char *,但您正试图将其分配给 integer = strtok_r(str2, delimiter2, &amp;saveptr2); 中的一个 char 数组。您的 integer 变量应该是 char *

【讨论】:

  • 谢谢!这是否意味着strtok_r 降低了可移植性并且仅在 linux 上可用?
  • 是的,它可能会降低便携性。然而 strtok_r 是由 posix 定义的,所以至少几乎所有类似 unix 的系统都会有它。
  • @i08in strtok_r 肯定会降低可移植性,因为它是 *​​nix 独有的功能,Windows 等效为 strtok_s
【解决方案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 **);

【讨论】:

    【解决方案4】:

    问题是函数strtok_r返回一个指向char的指针,你试图分配给一个char数组,所以为了让它工作你必须声明你的lineinteger变量作为char的指针,然后用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);
        }
      }
    }
    

    【讨论】:

    • 谢谢,这也很有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-20
    • 1970-01-01
    相关资源
    最近更新 更多