前言:
目前你们对“c语言missingbeforereturn”大致比较关心,姐妹们都想要学习一些“c语言missingbeforereturn”的相关文章。那么小编同时在网络上收集了一些对于“c语言missingbeforereturn””的相关资讯,希望你们能喜欢,咱们一起来学习一下吧!仅就从性能部分的错误诊断比较区别,之前见国外有相关文章,我做简单分享,但是,如果要了解区别,无妨从下文中包含的gcc和msvc阅读了解一下。
GCC和Clang一直在彼此较劲尝试证明谁的错误诊断更好。Clang首先在他们的“表现诊断”文章中讨论过GCC :
相关链接:
彼方唱罢我登场,而后在GCC改进了自己的诊断程序后,又发布了就其性能提升后的文章,标题是“Comparison of Diagnostics between GCC and Clang”,可以看到非常直白和露骨了......
相关链接:
我们可以通过测试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.csemicolon.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 x86Copyright (C) Microsoft Corporation. All rights reserved.
没错吧,
~ $ clang-6.0 -Wall semicolon.csemicolon.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.cmissingbrace.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.cmissingbrace.c(1): fatal error C1075: the left brace '{' was unmatched at the end of the fileint main(void) {Internal Compiler Error in Z:\opt\compiler-explorer\windows\19.10.25017\lib\native\bin\amd64_x86\cl.exe. You will be prompted to send an error report to Microsoft later.INTERNAL COMPILER ERROR in 'Z:\opt\compiler-explorer\windows\19.10.25017\lib\native\bin\amd64_x86\cl.exe' Please choose the Technical Support command on the Visual C++ Help menu, or open the Technical Support help file for more informationMicrosoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86Copyright (C) Microsoft Corporation. All rights reserved.
我认为我有可能搞错了, 但是看上去MSVC崩掉了。Microsoft系统可以的,除了崩掉MSVC再没缺点。
~ $ clang-6.0 -Wall missingbrace.cmissingbrace.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.coutofbounds.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失败漏洞:
相关链接:
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.cif-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 x86Copyright (C) Microsoft Corporation. All rights reserved.
MSVC呈现的至少是有意义的,完全不像clang搞出些垃圾来。
~ $ gcc-7 -Wall if-else-bug.cif-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("%s\n", string); return 0;}
~ $ gcc-7 -Wall -Wextra -pedantic string-concat.c~ $ clang-6.0 -Wall string-concat.cstring-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.cno-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.cno-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.cno-return.c(5) : warning C4716: 'doesNotReturnAValue': must return a valueno-return.c(12) : warning C4715: 'mightNotReturnAValue': not all control paths return a valueMicrosoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86Copyright (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.cppno-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 x86Copyright (C) Microsoft Corporation. All rights reserved.
对于微软,这点上,没什么好感,
~ $ g++-7 -Wall no-namespace.cppno-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.cppno-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 hereextern _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.cppcasting-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.cppcasting-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.cppcasting-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 x86Copyright (C) Microsoft Corporation. All rights reserved.
MSVC在上面这里胜出。虽然我感觉它有指向性的错误,但至少把这个问题正确报答出来了。
8轮下来总积分:Clang: 8,GCC: 5,MSVC: 6
特别补充说明,前面完全没有要说其中哪个很差劲,三者无疑各有优缺点, 但是,仅就诊断功能上来说clang被证明更强大些。
文章来源: