用ICC编译的代码与-O2一起使用,警告strtok和-O1崩溃

时间:2019-03-25 23:41:24

标签: c icc

我有一个文本文件,每行包含三列数据。前两个数字是整数,最后一个数字是双精度,即

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。

如果有人可以帮助我解决此问题,我非常感谢。

2 个答案:

答案 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>。谢谢大家!