[英]Code compiled with ICC works with -O2, warning about strtok and a crash with -O1
我有一個文本文件,每行包含三列數據。 前兩個數字是整數,最后一個是double,即
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
的以下警告消息,程序崩潰並出現分段錯誤:
<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
開關時,根本沒有警告,我的代碼可以正常運行而不會崩潰!
我使用的是英特爾2019編譯器和Linux操作系統。
如果有人能幫我解決這個問題,我真的很感激。
原因是你忘記了#include <string.h>
,它定義了strtok
的原型!
這個錯誤恰好在沒有通知的情況下通過,因為你明確地使用了C89模式, 並且因為C89允許隱式函數聲明(假定未聲明的函數返回int
) 並且因為英特爾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
級別 ,編譯器也會為真正的罪魁禍首輸出診斷信息:
<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不是符合標准的C編譯器。 它在診斷方面實際上很糟糕 。 它接受-Wall
作為“ -Wno-more
”的同義詞是不可接受的。
因此,如果測試代碼構建明顯更快,則始終使用其他編譯器來開發和ICC。
我忘了插入#include <string.h>
。 謝謝大家!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.