리눅스 개발 프로젝트를위한 Clang vs GCC


175

저는 대학에 있고 C를 사용하는 프로젝트를 위해 GCC와 Clang을 살펴 보았으며 Clang은 GCC보다 훨씬 사용자 친화적 인 것으로 보입니다. 결과적으로 Linux에서 C 및 C ++로 개발하기 위해 GCC와 달리 clang을 사용하는 이점과 단점이 무엇인지 궁금합니다.

제 경우에는 프로덕션이 아닌 학생 수준의 프로그램에 사용됩니다.

Clang을 사용하는 경우 GDB로 디버깅하고 GNU Make를 사용해야합니까, 아니면 다른 디버거를 사용하여 유틸리티를 만들어야합니까?


7
내가 알 수있는 한 Clang은 여전히 ​​표준 라이브러리 지원과 관련하여 여전히 "성숙하지"않았습니다. 그럼에도 불구하고 환상적인 오류 메시지가 있으므로 Clang에서 코드를 시도하여 항상 신비한 컴파일러 오류에 접근 할 수 있습니다. Clang은 C ++을 C로 컴파일 할 수도 있다고 생각합니다.
Kerrek SB

3
@ KerrekSB : "표준 라이브러리 지원"의 어떤 요소가 clang에서 빠졌습니까?
Stephen Canon

2
@StephenCanon : 마지막으로 시도했을 때 libstdc ++ (Clang의 일부가 아님)를 사용해야했습니다. 그리고 다른 날에 우리는 이 문제를 겪었습니다 . 어쨌든, 나는 출혈 가장자리를 따르고 있지 않으므로 내 견해가 완전히 쓸모 없을 수도 있습니다.
Kerrek SB

4
@ KerrekSB : 귀하의 링크와 관련하여 Clang은 순수한 Windows에서 작동하지 않습니다. 그래도 MinGW에서 작동합니다. 표준 라이브러리와 관련하여 현재 Clang의 실제 표준 라이브러리 부분은 없습니다. Clang은 OSX에서 libc ++와 함께 번들로 제공되지만 libc ++는 다른 환경에서 완전히 포팅되지 않으므로 이러한 Clang에서 다른 표준 라이브러리 구현을 설치해야합니다. Linux에서는 libstdc ++가 작동합니다.
Matthieu M.

1
@ KerrekSB : C ++ 98은 100 % 지원됩니다. C ++ 11은 대부분 지원됩니다 (마지막으로 확인 <atomic>했지만 지원되지 않습니다. 아마도 다른 작은 것들이 누락되었을 수 있습니다 ... 사용할 수 없으므로 완전히 속도를 낼 수는 없습니다).
제임스 맥닐리 스

답변:


122

편집하다:

gcc 사람들은 실제로 gcc (ah 경쟁)의 진단 경험을 개선했습니다. 그들은 여기에 그것을 보여주는 위키 페이지를 만들었습니다 . gcc 4.8의 진단 기능도 향상되었습니다 (gcc 4.9x 추가 색상 지원). Clang은 여전히 ​​선두에 있지만 격차는 좁혀지고 있습니다.


실물:

학생들에게는 무조건 Clang을 추천합니다.

gcc와 Clang 사이에서 생성 된 코드 측면에서 성능이 명확하지 않습니다 (gcc 4.7이 여전히 선두를 가지고 있다고 생각하지만 아직 결정적인 벤치 마크는 보지 못했습니다).

반면 Clang의 매우 명확한 진단은 초보자가 쉽게 이해할 수 있습니다.

이 간단한 스 니펫을 고려하십시오.

#include <string>
#include <iostream>

struct Student {
std::string surname;
std::string givenname;
}

std::ostream& operator<<(std::ostream& out, Student const& s) {
  return out << "{" << s.surname << ", " << s.givenname << "}";
}

int main() {
  Student me = { "Doe", "John" };
  std::cout << me << "\n";
}

Student클래스 정의 후에 세미콜론이 누락되었음을 바로 알 수 있습니다 .

글쎄, gcc 는 유행 후에도 그것을 주목한다 .

prog.cpp:9: error: expected initializer before ‘&’ token
prog.cpp: In function int main()’:
prog.cpp:15: error: no match for operator<<’ in std::cout << me
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:112: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:121: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:131: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:169: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:173: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:177: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:97: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:184: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:111: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:195: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:204: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:208: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:213: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:217: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:225: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:229: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:125: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]

그리고 Clang도 여기에 정확하게 출연하지는 않지만 여전히 :

/tmp/webcompile/_25327_1.cc:9:6: error: redefinition of 'ostream' as different kind of symbol
std::ostream& operator<<(std::ostream& out, Student const& s) {
     ^
In file included from /tmp/webcompile/_25327_1.cc:1:
In file included from /usr/include/c++/4.3/string:49:
In file included from /usr/include/c++/4.3/bits/localefwd.h:47:
/usr/include/c++/4.3/iosfwd:134:33: note: previous definition is here
  typedef basic_ostream<char>           ostream;        ///< @isiosfwd
                                        ^
/tmp/webcompile/_25327_1.cc:9:13: error: expected ';' after top level declarator
std::ostream& operator<<(std::ostream& out, Student const& s) {
            ^
            ;
2 errors generated.

나는 전형적인 "오 나의 신 Clang 내 마음을 읽었습니다"예제보다는 불명확 한 오류 메시지 (문법의 모호함에서 나온)를 유발하는 예제를 의도적으로 선택합니다. 그럼에도 불구하고 Clang은 오류의 홍수를 피합니다. 학생들을 놀라게 할 필요가 없습니다.


2
음 ... 지난번에 확인한 결과, clang이 테스트에서 물에서 gcc를 거의 날려 버린 다양한 벤치 마크를 게시 한 기사를 읽었습니다. 출처 : clang.llvm.org/features.html#performance

31
@AscensionSystems :이 테스트는 컴파일하는 바이너리의 성능이 아니라 Clang 바이너리 자체의 성능을 보여줍니다.
Matthieu M.

컴파일 된 실행 파일을 비교해 보는 것이 좋습니다. 나는 clang이 최적화에서 훨씬 더 잘 작동한다는 인상을 받고 있지만 실제로 어떤 벤치 마크도 보지 못했습니다. 제가 그것을 확인해 보겠습니다.

4
@ AscensionSystems : gcc 4.6을 llvm 3.0 과 비교하여 gcc의 평균 이점을 보여주는 최신 벤치가 있습니다. DragonEgg 벤치 도 흥미 롭다 . DragonEgg는 gcc 프론트 엔드 (및 최적화 프로그램)를 사용한 다음 LLVM 백엔드를 사용하여 코드를 생성 할 수있는 플러그인이다.
Matthieu M.

1
내가 마지막으로 확인했을 때, phoronix 벤치 마크는 신뢰할 수 없었습니다. 컴파일러 플래그는 제대로 문서화되지 않았지만 결과는 올바르게 설정되지 않았다고 제안했습니다.
Eamon Nerbonne

35

현재 GCC는 Clang보다 C ++ 11 기능을 훨씬 더 완벽하고 완벽하게 지원합니다. 또한 GCC의 코드 생성기는 Clang의 코드 생성기보다 더 나은 최적화를 수행합니다 (제 경험으로는 철저한 테스트를 보지 못했습니다).

반면에 Clang은 종종 GCC보다 코드를 더 빨리 컴파일하고 코드에 문제가있을 때 더 나은 오류 메시지를 생성합니다.

어떤 것을 사용할지 선택하는 것은 실제로 당신에게 중요한 것이 무엇인지에 달려 있습니다. 컴파일의 편의성을 높이는 것보다 C ++ 11 지원과 코드 생성 품질을 중요하게 생각합니다. 이 때문에 GCC를 사용합니다. 당신에게 장단점은 다를 수 있습니다.


3
다음은 GCC 4.6과 Clang 3.0 을 비교 한 최신 Phoronix 기사 와 불도저 플랫폼에 대한 이전 기사 입니다. 벤치 마크에 따라 승자는 하나 또는 다른 것입니다 (이전 기사에서 gcc 4.7도 나타납니다).
Matthieu M.

왜 둘 다 사용하지 않습니까? 개발을위한 Clang, 생산을위한 GCC
segfault

5
@segfault : 이것이 제가 현재하고있는 일입니다. 이 답변은 상당히 오래되었으며 더 이상 사실이 아닙니다. Clang과 GCC는 내가 작성한 이후 크게 향상되었습니다 (특히 Clang은 이제 GCC 전체 C ++ 11 지원과 일치하고 GCC는 오류 메시지와 컴파일 속도가 향상되었습니다). 이제 Clang 소스 코드가 GCC 소스보다 이해하기 훨씬 쉽기 때문에 Clang을 약간 선호하여 둘 다 사용하는 것이 좋습니다.
Mankarse

23

때로는 서로 다르고 유용한 오류 메시지가 표시되기 때문에 둘 다 사용합니다.

파이썬 프로젝트는 핵심 개발자 중 한 명이 처음으로 clang으로 컴파일을 시도했을 때 많은 작은 버그 릿을 찾아서 고칠 수있었습니다.


1
디버그 빌드에는 clang을 사용하고 최적화 된 릴리스에는 gcc를 사용하는 것에 대해 어떻게 생각하십니까?
Olical

5
Clang으로 개발하고 GCC로 릴리스하는 것이 합리적이지만 GCC 릴리스가 테스트 스위트를 통과하는지 확인하십시오 (NDEBUG가 있거나없는).
Raymond Hettinger

2
답변 주셔서 감사합니다. 나는 그것을 조금 시도해 보았고 실제로 잘 작동합니다. 나는 다른 경고 세트도 얻습니다.
Olical

11

나는 연타가 유용한 경고를 가지고 있지만, 내 자신의 광선 추적 벤치 마크 발견, 연타 및 GCC 모두 사용 -는 지속적으로 5~15%를 느리게 다음 GCC (물론 소금의 입자로 가져가,하지만 비슷한 최적화 플래그를 사용하려고 모두).

그래서 지금은 복잡한 매크로와 함께 Clang 정적 분석 및 경고를 사용합니다. (지금은 GCC의 경고가 거의 우수합니다-gcc4.8-4.9).

몇 가지 고려 사항 :

  • Clang은 OpenMP를 지원하지 않으며,이를 활용하는 경우에만 중요하지만 그렇게하므로 나에게 한계가 있습니다. (*****)
  • 크로스 컴파일은 잘 지원되지 않을 수 있습니다 (예 : FreeBSD 10은 여전히 ​​ARM에 GCC4.x를 사용함). gcc-mingw는 Linux ... (YMMV)에서 사용할 수 있습니다.
  • 일부 IDE는 아직 Clangs 출력 구문 분석 ( 예 : ***** 과 같은 QtCreator)을 지원하지 않습니다 . 편집 : QtCreator는 이제 Clang의 출력을 지원합니다
  • GCC의 일부 측면은 더 잘 문서화되어 있으며 GCC는 오래 전부터 사용되어 왔으므로 널리 사용되므로 경고 / 오류 메시지에 대한 도움을받는 것이 더 쉬울 수 있습니다.

*****- 이 영역은 현재 개발 중이며 곧 지원 될 수 있습니다.


OpenMP도 사용하지만 Clang과 함께 작동하는 TBB로 전환하려고 생각합니다.

1
TBB는 일부 경우 OpenMP를 대체 할 수있는 대안 일 수 있습니다 (그러나 내가 알 수있는 한 C ++에만 해당). 어쨌든 OpenMP를 지원하십시오.
ideasman42

7

학생 레벨 프로그램의 경우 Clang은 기본적으로 더 엄격한 wrt라는 이점이 있습니다. C 표준. 예를 들어, 다음 K & R 버전의 Hello World는 GCC에 의해 경고없이 허용되지만 Clang에 의해 일부 설명적인 오류 메시지와 함께 거부됩니다.

main()
{
    puts("Hello, world!");
}

GCC를 사용하면 -Werror유효한 C89 프로그램이 아니라는 사실을 알 수 있도록해야합니다. 또한 C99 언어 를 사용 c99하거나 gcc -std=c99구해야합니다.


8
gcc일반적 -Wall으로이 프로그램에 대해 경고하는 적어도로 ​​호출해야 합니다. clang그래도 좋은 경고 / 오류가 발생합니다.
caf

2
@ caf : 이것은 내가 만들고자하는 요점입니다 .GCC를 사용하면 옵션을 전달해야합니다. 기본적으로는 교육 목적으로 너무 관대 할 수 있습니다.
Fred Foo

사실 일 수도 있지만 상당히 사소한 점입니다. 더 중요한 것은 오류 메시지 의 품질 입니다. CCC가 실제로 마술을하고 있다는 것을 이해하지만 GCC 4.6은 꽤 좋아졌습니다.
Kerrek SB

2
@dreamlax : 맞습니다; 이이기도 gnu99하고 gnu++98gnu++0x. 나는 이것이 진정한 확장 이라고 생각합니다 . 즉, 문제없이 ISO 표준 코드를 컴파일합니다. 세부 사항은 다음과 같습니다. C , C ++ .
Kerrek SB

1
이 프로그램은 오류나 경고를 생성하지 않아야합니다. 표준을 준수합니다.
Miles Rout

3

나는 clang이 대안이 될 수 있다고 생각합니다.

GCC와 clang은와 같은 표현에 약간의 차이 a+++++a가 있으며 gcc를 사용하는 동안 Mac에서 clang을 사용하는 동료와는 다른 많은 답변을 얻었습니다.

GCC가 표준이되었으며 clang이 대안이 될 수 있습니다. GCC는 매우 안정적이며 clang은 아직 개발 중입니다.


5
Clang은 Linux 세계에서 GCC를 완전히 대체하기 위해 신속하게 준비하고 있으며 BSD 세계에서도 크게 그러했습니다. 몇 년 전 Mac의 GCC를 대체했습니다. 클랑은 좋은 물건입니다. 저는 GCC가 개인적으로 대안이 될 수 있다고 생각합니다.
coder543

5
a +++++ a 표현은 정의되어 있지 않으므로 각 컴파일러 또는 심지어 동일한 컴파일러의 다른 버전에서도 다른 답변을 얻을 것으로 예상됩니다. 다른 시간에 컴파일 할 때 동일한 컴파일러에서 해당 표현식에 대해 다른 결과를 얻을 수도 있습니다. 그것이 "정의되지 않은"의 의미입니다.
Lelanthran

1
a+++++aa ++ ++ + a구문 오류로 구문 분석되었으므로 실패해야 합니다.
Miles Rout

@Lelanthran은 정의되지 않은 의미가 아닙니다. 정의되지 않은 동작이 있으므로 컴파일러가 컴파일에 실패하거나 런타임에 throw하거나 CPU를 잠글 수 있으므로 하드 리셋이나 더 불길한 일을해야합니다.
Antti Haapala
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.