日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

僅就從性能部分的錯誤診斷比較區別,之前見國外有相關文章,我做簡單分享,但是,如果要了解區別,無妨從下文中包含的gcc和msvc閱讀了解一下。

GCC和Clang一直在彼此較勁嘗試證明誰的錯誤診斷更好。Clang首先在他們的“表現診斷”文章中討論過GCC :

相關鏈接:
https://clang.llvm.org/diagnostics.html

彼方唱罷我登場,而后在GCC改進了自己的診斷程序后,又發布了就其性能提升后的文章,標題是“Comparison of Diagnostics between GCC and Clang”,可以看到非常直白和露骨了......

相關鏈接:
https://gcc.gnu.org/wiki/ClangDiagnosticsComparison

我們可以通過測試Clang 6.0.0、GCC 7.3.0中常見錯誤,同時通過編譯器資源管理器MSVC 2017 19.10.25107來檢驗誰的性能更好。需要特別說明的是GCC 8似乎已改進了某些消息,但它仍舊不能算是一個穩定的版本。

我個人是把MSVC和Clang中的靜態分析器排除在外的,因為將他們中的分析器拿來與GCC這方面的缺失做相應的比較,肯定是不公平的,由此,僅使用-Wall或/ W3,除非沒有發現錯誤,否則我將嘗試-Weverything,-Wextra -Wpedantic或/ Wall。

 

第一輪:關于“分號”的缺失

忘記分號,一直都是這樣的

semicolon.c

#include <stdio.h>

int main(void) {
    printf("Hello, world!n") // no semicolon
    return 0 // no semicolon
}

這是在printf語句和return語句之后的慣常會丟失的分號,類似這樣一個常見的錯誤,應該開始意識到這個問題了吧,再如

~ $ gcc-7 -Wall semicolon.c 
semicolon.c: In function 'main':
semicolon.c:5:5: error: expected ';' before 'return'
     return 0 // no semicolon        
     ^~~~~~

 

C:> cl /W3 /diagnostics:caret semicolon.c
semicolon.c(5,5): error C2143: syntax error: missing ';' before 'return'
    return 0 // no semicolon
    ^
semicolon.c(6,1): error C2143: syntax error: missing ';' before '}'
}
^
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

沒錯吧,

~ $ clang-6.0 -Wall semicolon.c
semicolon.c:4:30: error: expected ';' after expression
    printf("Hello, world!n") // no semicolon
			     ^
			     ;
semicolon.c:5:13: error: expected ';' after return statement
    return 0 // no semicolon
	    ^
	    ;
2 errors generated.

Clang顯然是贏家,其次是MSVC。而GCC沒法識別第二個錯誤。MSVC和GCC會僵硬的出現把 ';' 放在 'return'"之前的 errors,技術上這來講,說得通,但不太聰明。

第一輪打分:Clang: 2, GCC: 0, MSVC: 1

 

第二輪:缺花括號

在函數末尾丟失花括號是另一個常見錯誤,盡管不如前一個常見。

missingbrace.c

int main(void) {
    return 0;
// no closing brace

希望GCC或MSVC能夠把這個問題解決了,

~ $ gcc-7 -Wall missingbrace.c
missingbrace.c: In function 'main':
missingbrace.c:2:5: error: expected declaration or statement at end of input
     return 0;
     ^~~~~~

實在糟糕透頂,

C:> cl /W3 /diagnostics:caret missingbrace.c
missingbrace.c(1): fatal error C1075: the left brace '{' was unmatched at the end of the file
int main(void) {
Internal Compiler Error in Z:optcompiler-explorerwindows19.10.25017libnativebinamd64_x86cl.exe.  You will be prompted to send an error report to Microsoft later.
INTERNAL COMPILER ERROR in 'Z:optcompiler-explorerwindows19.10.25017libnativebinamd64_x86cl.exe'
    Please choose the Technical Support command on the Visual C++
    Help menu, or open the Technical Support help file for more information
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

我認為我有可能搞錯了, 但是看上去MSVC崩掉了。Microsoft系統可以的,除了崩掉MSVC再沒缺點。

~ $ clang-6.0 -Wall missingbrace.c
missingbrace.c:2:14: error: expected '}'
    return 0;
	     ^
missingbrace.c:1:16: note: to match this '{'
int main(void) {
	       ^
1 error generated.

仍舊,Clang收入2分.

1-2輪積分情況: Clang: 4,GCC: 0,MSVC: 2

 

第三輪:out of bounds

又一個非常常見的錯誤,

outofbounds.c
#include <stdio.h>

static const int array[4] = { 1, 2, 3, 4 };

int main(void) {
    for (int i = 0; i <= 4 /* should be < */; i++) {
        printf("%d ", array[i]);
    }
    return 0;
}

頗為有趣的是, 即使用 -Warray-bounds 或者 /Wall,Clang、MSVC都未曾搞清這點。

但是,在使用-O2時,GCC實際上呈現出的是進行更改的正確選擇!

~ $ gcc-7 -Wall -O2 outofbounds.c
outofbounds.c: In function 'main':                    
outofbounds.c:7:9: warning: iteration 4 invokes undefined behavior [-Waggressive-loop-optimizations]
        printf("%d ", array[i]);
        ^~~~~~~~~~~~~~~~~~~~~~~
outofbounds.c:6:5: note: within this loop
    for (int i = 0; i <= 4 /* should be < */; i++) {
    ^~~

不過,GCC在這里只得到一點,因為它并不總是顯示此錯誤。

1-3輪積分情況: clang:4,GCC:1,MSVC:2

 

第四輪: ifs 無花括號

ifs沒有花括號,盡管它們顯得很方便,但帶來的危害往往大于弊端,例如惡名遠揚的goto失敗漏洞:

相關鏈接:
https://nakedsecurity.sophos.com/2014/02/24/anatomy-of-a-goto-fail-Apples-ssl-bug-explained-plus-an-unofficial-patch/

if-else-bug.c

#include <stdio.h>

int main(int argc, char**argv) {
    if (argc > 1) // needs braces
        argc--;
        argv++;
    else
        printf("Usage: %s <arguments>n", *argv); // (this would theoretically be UB because of the argv++)
    return 0;
}

自然地作為Apple的編譯器,Clang是應該意識到這個錯誤的,

~ $ clang-6.0 -Wall if-else-bug.c
if-else-bug.c:8:5: error: expected expression
    else
    ^
1 error generated.

……這是一個非常無用的錯誤,也難怪蘋果沒有發現。

C:> cl /W3 /diagnostics:caret if-else-bug.c
(7): error C2181: illegal else without matching if
    else
    ^
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MSVC呈現的至少是有意義的,完全不像clang搞出些垃圾來。

~ $ gcc-7 -Wall if-else-bug.c
if-else-bug.c: In function 'main':
if-else-bug.c:5:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
     if (argc > 1) // needs braces
     ^~
if-else-bug.c:7:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
         argv++;
         ^~~~
if-else-bug.c:8:5: error: 'else' without a previous 'if'
     else
     ^~~~

沒想到,GCC有次一次鶴立雞群了下,

1-4輪積分情況: Clang: 4,GCC: 3,MSVC: 2

 

第五輪:JAVA風格的字符串連接

Java、JavaScript、C ++(一定程度上)和其他幾種語言使你可以使用'+'來連接字符串和其他內容。C并沒有達到你的期望。

字符串concat.c

#include <stdio.h>

int main(void) {
    int value = 4;
    const char *string = "value = " + value; // This isn't Java!
    printf("%sn", string);
    return 0;
}

 

~ $ gcc-7 -Wall -Wextra -pedantic string-concat.c
~ $ clang-6.0 -Wall string-concat.c
string-concat.c:5:37: warning: adding 'int' to a string does not append to the string [-Wstring-plus-int]
    const char *string = "value = " + value; // This isn't Java!
                         ~~~~~~~~~~~^~~~~~~
string-concat.c:5:37: note: use array indexing to silence this warning
    const char *string = "value = " + value; // This isn't Java!
                                    ^
                         &          [      ]
1 warning generated.

GCC和MSVC 在這件事上完全沒搞定,而clang給出了一個有用的報錯.

1-5輪積分情況:Clang: 6,GCC: 3, MSVC: 2

 

第六輪:忘記返回值

有時,你忘記了一個函數需要返回一個值,或者忘記在這個switch語句之后放置一個return語句,或者還有其它種種,

no-return.c

no-return.c

#include <stdlib.h>

int doesNotReturnAValue(void) {
    // no return value
}

int mightNotReturnAValue(void) {
    if (rand() % 2 == 0) {
        return 2;
    }
    // if rand() is odd, there is no return value
}

 

~ $ gcc-7 -Wall no-return.c
no-return.c: In function 'doesNotReturnAValue':
no-return.c:5:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
no-return.c: In function 'mightNotReturnAValue':
no-return.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
~ $ clang-6.0 -Wall no-return.c
no-return.c:5:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
no-return.c:12:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
2 warnings generated.

啊,0分,完全沒價值

C:> cl /W3 /diagnostics:caret no-return.c
no-return.c(5) : warning C4716: 'doesNotReturnAValue': must return a value
no-return.c(12) : warning C4715: 'mightNotReturnAValue': not all control paths return a value
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MSVC做到了。

1-6輪積分情況:Clang: 6,GCC: 3,MSVC: 4

 

第七輪:忘記命名空間

是時候來一些C ++了!

我經常犯的錯誤包括,忘記添加“使用命名空間”或是在調用之前放置命名空間。

no-namespace.cpp

#include <IOStream>

int main() {
    cout << "Hello, world!n"; // should be std::cout
    return 0;
}

讓我們看看編輯器怎么呈現

C:> cl /W3 /diagnostics:caret no-namespace.cpp
no-namespace.cpp(4): error C2065: 'cout': undeclared identifier
    cout << "Hello, world!n"; // should be std::cout
    ^
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

對于微軟,這點上,沒什么好感,

~ $ g++-7 -Wall no-namespace.cpp
no-namespace.cpp: In function 'int main()':
no-namespace.cpp:4:5: error: 'cout' was not declared in this scope
     cout << "Hello, world!n"; // should be std::cout
     ^~~~
no-namespace.cpp:4:5: note: suggested alternative:
In file included from no-namespace.cpp:1:0:
/usr/include/c++/7.3.0/iostream:61:18: note:   'std::cout'
   extern ostream cout;  /// Linked to standard output
                  ^~~~

這個看上去好些, 雖然返回的消息有點迷,但是GCC能夠搞清楚我們指的是std::cout。再看看clang。

~ $ clang++-6.0 -Wall no-namespace.cpp
no-namespace.cpp:4:5: error: use of undeclared identifier 'cout'; did you mean 'std::cout'?
    cout << "Hello, world!n"; // should be std::cout
    ^~~~
    std::cout
/usr/include/c++/v1/iostream:54:33: note: 'std::cout' declared here
extern _LIBCPP_FUNC_VIS ostream cout;
                                ^
1 error generated.

好吧,對于clang來說,雖然和GCC顯示了相同的信息,但還是和GCC有所區別的,clang能直接的問到點子上“你是否是指std::cout",而后才會去執行,clang兩分,GCC得一分.

1-7輪積分情況: Clang: 8,GCC: 4,MSVC: 4

 

第八輪:dynamic_casting,一個類本身

C ++ dynamic_cast應該在指向類的指針上使用,而不是在類本身上使用,這是蠻奇怪的。

casting-a-class.cpp

class Base {};
class Derived : public Base {};

int main() {
    Base base;
    Derived derived = dynamic_cast<Derived>(base); // should be used on a pointer
    return 0;
}

 

~ $ clang++-6.0 -Wall casting-a-class.cpp
casting-a-class.cpp:6:23: error: 'Derived' is not a reference or pointer
    Derived derived = dynamic_cast<Derived>(base); // should be a pointer
                      ^           ~~~~~~~~~
1 error generated.

天吶,這塊clang竟然報錯,

~ $ g++-7 -Wall casting-a-class.cpp
casting-a-class.cpp: In function 'int main()':
casting-a-class.cpp:6:49: error: cannot dynamic_cast 'base' (of type 'class Base') to type 'class Derived' (target is not pointer or reference)
     Derived derived = dynamic_cast<Derived>(base); // should be a pointer
                                                 ^

這點上看,GCC更清晰一些,雖然我不知道它指向的是什么。

C:> cl /W3 /diagnostics:caret casting-a-class.cpp
casting-a-class.cpp(6,49): error C2680: 'Derived': invalid target type for dynamic_cast
    Derived derived = dynamic_cast<Derived>(base); // should be used on a pointer
                                                ^
casting-a-class.cpp(6,49): note: target type must be a pointer or reference to a defined class
    Derived derived = dynamic_cast<Derived>(base); // should be used on a pointer
                                                ^
Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

MSVC在上面這里勝出。雖然我感覺它有指向性的錯誤,但至少把這個問題正確報答出來了。

8輪下來總積分:Clang: 8,GCC: 5,MSVC: 6

特別補充說明,前面完全沒有要說其中哪個很差勁,三者無疑各有優缺點, 但是,僅就診斷功能上來說clang被證明更強大些。

 

文章來源:
https://easyaspi314.github.io/gcc-vs-clang.html

分享到:
標簽:編譯器
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定