Неявное объявление функции «strtok_r», несмотря на включение ‹string.h›

У меня есть следующий код для токенизации строки, содержащей строки, разделенные \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.

Приветствуются любые идеи о том, как я могу удалить предупреждение.

Я использую gcc 4.8.2 на 64-битном рабочем столе Ubuntu 14.04.


person jobin    schedule 30.05.2014    source источник
comment
Что касается вашего неявного объявления, strtok_r следует правильно ввести с помощью string.h, но это функция POSIX-2001, и вы должны убедиться, что она включена. Либо #define _POSIX_C_SOURCE 200112L перед включением любого из стандартных заголовков, либо укажите его с помощью параметра -D в ваших переключателях командной строки для вашего компилятора. Это, конечно, при условии, что ваша реализация поддерживает это, и я, конечно, ожидаю, что ваша.   -  person WhozCraig    schedule 30.05.2014
comment
@WhozCraig: я не вижу использования #define _POSIX_C_SOURCE на странице руководства для strtok_r, откуда мне знать, что я должен это делать?   -  person jobin    schedule 30.05.2014
comment
См. Требования к макросам для тестирования функций в < b>справочная страница. Я предполагаю, что вы используете glibc на своей платформе. Есть и другие способы его всасывания, некоторые из которых могут быть предопределены по умолчанию, когда вы устанавливаете свой стандартный переключатель (например, -std=c99, скорее всего, не включит его, а -std=c11, вероятно, включит). не проверял это, но я не удивлюсь).   -  person WhozCraig    schedule 30.05.2014
comment
@WhozCraig: Спасибо! Ваш комментарий вместе с ответом nos помог решить эту проблему. Большое спасибо! :)   -  person jobin    schedule 30.05.2014
comment
возможно дублированный вопрос. проверьте этот stackoverflow.com/questions/2246618/ и этот stackoverflow.com/questions/19388774/   -  person CS Pei    schedule 30.05.2014
comment
@JohnSmith: Похоже, это не так, это специально для модулей ядра.   -  person jobin    schedule 30.05.2014


Ответы (4)


strtok_r не является стандартной функцией C. Вы запросили только C99, используя флаг -std=c99compiler, поэтому файлы заголовков (из glibc) сделают доступными только стандартные функции C99 в string.h.

Включите расширения, используя -std=gnu99 или определив одно из расширений, показанных на справочной странице strtok, которое поддерживает strtok_r перед включением string.h. Например.

#define _GNU_SOURCE
#include <string.h>

Обратите внимание, что у кода есть и другие проблемы: strtok_r возвращает char * , но вы пытаетесь присвоить это массиву символов в integer = strtok_r(str2, delimiter2, &saveptr2);. Ваша переменная integer должна быть char *

person nos    schedule 30.05.2014
comment
Спасибо! Означает ли это, что strtok_r уменьшает переносимость и доступно только в Linux? - person jobin; 30.05.2014
comment
Да, это может снизить переносимость. Однако strtok_r определяется posix, поэтому, по крайней мере, почти все unix-подобные системы будут иметь его. - person nos; 30.05.2014
comment
@ i08in strtok_r определенно снижает переносимость, поскольку это функция только для * nix, эквивалентом Windows является strtok_s. - person MDMoore313; 11.11.2015

Та же проблема с GCC 7.4.2 в Debian

Решено с помощью __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 **);
person David Ranieri    schedule 30.05.2014

проблема в том, что функция strtok_r возвращает указатель на char, ведь вы пытаетесь присвоить массив char, поэтому, чтобы заставить его работать, вам нужно объявить переменные line и integer как указатель на 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);
    }
  }
}
person Cristofor    schedule 30.05.2014
comment
Спасибо, это тоже было полезно! - person jobin; 30.05.2014

Я тоже использую 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;.

Для предупреждения о неявном объявлении проверьте это

Могу ли я использовать strtok() в модуле ядра Linux?

person CS Pei    schedule 30.05.2014
comment
line и integer раньше были char *. Я изменил это, предполагая, что ошибки сегмента были вызваны назначением указателя на символ, но изменение этого не помогло: вы можете попробовать изменить line на char* вместо char line[200]. Разве вы не получаете предупреждения о неявном объявлении strtok_r при их компиляции с использованием параметров gcc, которые я упомянул в вопросе? - person jobin; 30.05.2014
comment
Я надеюсь, вы использовали параметры gcc, которые я упомянул в вопросе, не так ли? - person jobin; 30.05.2014
comment
Есть причины, по которым вы это пропустили? Я включил это как часть того, что я прочитал, как рекомендуемые параметры, которые я должен использовать при компиляции программ C здесь, на SO. - person jobin; 30.05.2014
comment
Спасибо, вы дали отличное представление о причине, но ни один ответ не помог ее решить. - person jobin; 30.05.2014