Причина в том, что вы забыли #include <string.h>
, который определяет прототип для strtok
!
Эта ошибка прошла без уведомления только потому, что вы явно использовали режим C89 и , потому что C89 допускает неявные объявления функций (где предполагается, что необъявленная функция возвращает int
) и потому что компилятор Intel C глючит!
Я упростил код до:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE* f = fopen("foo", "r");
char line[1024];
char* pch;
fgets(line, sizeof(line), f);
pch = strtok(line, " \t");
}
Когда скомпилировано с -std=c89
и -O1
ICC-отчеты
<source>(9): warning #556: a value of type "int" cannot be assigned to an entity
of type "char *"
pch = strtok(line, " \t");
^
Если скомпилировано с -O2
, предупреждение исчезло! Но это не соответствует C89 3.3.16.1 Простое назначение , которое говорит, что
Ограничения
Должно быть одно из следующего: [42]
левый операнд имеет квалифицированный или неквалифицированный арифметический тип, а правый имеет арифметический тип;
левый операнд имеет квалифицированную или неквалифицированную версию структуры или типа объединения, совместимого с типом правого;
оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов, а тип, на который указывает слева, содержит все квалификаторы типа, на который указывает справа;
один операнд является указателем на объект или неполный тип, а другой - указателем на квалифицированную или неквалифицированную версию void, а тип, на который указывает левый, имеет все квалификаторы типа, на который указывает право; или
левый операнд является указателем, а правый - константой нулевого указателя.
Ни одна из 5 пуль не соответствует. Поскольку ограничение нарушено, совместимый компилятор должен выдать диагностическое сообщение , которое ICC не выполняет .
Однако, если бы вы использовали режим -std=c11
, даже на -O2
level , компилятор выведет диагностику для истинного виновника:
<source>(9): warning #266: function "strtok" declared implicitly
pch = strtok(line, " \t");
^
Compiler returned: 0
т.е. в отсутствие существующего объявления для strtok
компилятор использовал правило C89 для неявного объявления функции и неявно предполагал, что функция будет объявлена как
int strtok();
Но это нарушает ревизию 2011 года, которая больше не имеет неявных объявлений функций , и по этой причине выводится диагностическое сообщение.
Наконец, следует отметить, насколько действительно ужасно плох, диагностика ICC . Если вы используете -std=c89 -O2 -Wall -Wextra
для моей программы, вы все равно не получите никаких предупреждений !
Основные выносы:
никогда не используйте режим C89 . Это 30 лет. Он того же возраста, что и Windows 2.1x и MSDOS 4.0 и Mac System 6 . Вы бы их тоже не использовали. Обратите внимание, что даже версия, более поздняя, чем ICC 16.0.3, кажется, по умолчанию в режиме C89.
ICC не является стандартным компилятором Си. Это на самом деле плохо при диагностике. То, что он принимает -Wall
как синоним для "-Wno-more
" , недопустимо.
Поэтому всегда используйте другие компиляторы для разработки, а ICC только для тестируемых сборок кода, если это заметно быстрее.