我有一个文本文件,每行包含三列数据。前两个数字是整数,最后一个数字是双精度,即
1 2 3.45
4 42 3.45
... and so forth...
我正在使用以下C代码从文件中仅仅读取第一行。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
long int m, n;
double val;
FILE* f = fopen("input.txt", "r");
char line[1024];
char* pch;
fgets(line, sizeof(line), f);
pch = strtok(line, " \t"); //** warning
n = strtol(pch, NULL,10);
pch = strtok(NULL, " \t"); //** warning
m = strtol(pch, NULL,10);
pch = strtok(NULL, " \t"); //** warning
val = strtod(pch, NULL);
...
}
但是,当我尝试使用-std=c89 -Wall -Wextra -O1
开关编译代码时,对于每个strtok
我都会收到以下 warning 消息,并且程序会因分段错误而崩溃:>
<source>(9): warning #556: a value of type "int" cannot be assigned to an entity
of type "char *"
pch = strtok(line, " \t");
^
...
Compiler returned: 0
但是当我尝试使用-O2
或-O3
开关时,根本没有任何警告,并且我的代码可以正常工作!
我正在使用Intel 2019编译器和Linux OS。
如果有人可以帮助我解决此问题,我非常感谢。
答案 0 :(得分:4)
原因是您忘记了#include <string.h>
,它为strtok
定义了原型!
此错误恰好在没有通知的情况下通过,是因为您显式使用了C89模式,并且是因为C89允许隐式函数声明(假定未声明的函数返回int
)< strong> ,因为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");
}
compiled with -std=c89
and -O1
ICC报告
<source>(9): warning #556: a value of type "int" cannot be assigned to an entity
of type "char *"
pch = strtok(line, " \t");
^
如果compiled with -O2
,警告消失了!但这不符合C89 3.3.16.1 Simple assignment所说的
约束
应满足以下条件之一:[42]
左操作数具有合格或不合格的算术类型,而右操作数具有算术类型;
左操作数具有与右类型兼容的结构或联合类型的合格或不合格版本;
这两个操作数都是指向兼容类型的合格或不合格版本的指针,并且左侧指向的类型具有右侧指向的类型的所有限定符;
一个操作数是一个指向对象或不完整类型的指针,另一个是一个指向void的合格或不合格版本的指针,并且左侧指向的类型具有由指向的所有类型的限定符正确的;或
左边的操作数是一个指针,右边的是一个空指针常量。
5个项目符号都不匹配。由于违反了约束,因此兼容的编译器必须发出诊断消息, ICC不这样做。
但是,如果您已使用-std=c11
模式,even on -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
用于我的程序摘录,则您still receive no warnings whatsoever!
主要要点是:
从不使用C89模式。这是30岁。它与 Windows 2.1x 和 MSDOS 4.0 和 Mac System 6 的年龄相同。您也不会使用它们。 请注意,即使是ICC 16.0.3以后的版本也似乎默认为C89模式。
ICC不是符合标准的C编译器。实际上,它对诊断来说不好。它接受-Wall
作为“ -Wno-more
” 的同义词是不可接受的。
因此,如果证明速度更快,则始终使用其他编译器进行开发,并且仅对经过测试的代码构建使用ICC。
答案 1 :(得分:3)
我忘记插入#include <string.h>
。谢谢大家!