성능을 위해 C로 작성 하시겠습니까? [닫은]


32

나는 C가 일반적으로 C ++보다 성능 이점이 있다고 들었습니다. MSVC가 최신 표준 C를 지원하지 않는 것 같지만 최신 C99를 지원한다는 사실을 알기 전까지는 다른 생각은 없었습니다.

OpenGL에서 렌더링 할 코드를 사용하여 라이브러리를 작성하여 재사용 할 수 있도록 계획하고있었습니다. 그래픽과 관련하여 성능 향상을 환영하므로 C로 라이브러리를 작성하려고했습니다.

그러나 정말로 가치가 있습니까? 라이브러리를 사용하는 코드는 C ++로 작성되었을 가능성이 높으며 일반적으로 C ++로 코딩하는 것을 선호합니다.

그러나 성능에 약간의 차이가 생길 경우 C로 갈 것입니다.

이 라이브러리는 Windows / OS X / Linux에서 작동하도록 만들 수 있으며 모든 것을 기본적으로 컴파일 할 것입니다 (Windows의 경우 MSVC, OS X의 경우 Clang 또는 GCC, Linux의 경우 GCC). 또는 인텔의 모든 컴파일러).

나는 주변을 둘러 보았고 벤치 마크 등을 찾았지만 내가 본 모든 것은 MSVC 및 Clang 대신 GCC를 다루었습니다. 또한 벤치 마크에는 사용 된 언어의 표준이 언급되어 있지 않습니다. 아무도 이것에 대해 생각이 있습니까?

편집하다:몇 년 동안 더 경험을 쌓은 후이 질문에 대한 견해를 나누고 싶었습니다. C ++ 에서이 질문을하는 프로젝트를 작성했습니다. 우리가 할 수있는 작은 양의 성능을 얻기 위해 C에서 같은 시간에 다른 프로젝트를 시작했고 C에서 프로젝트를 연결할 수 있어야했습니다. 문자열 조작. 나는 C ++ 표준 라이브러리 에서이 기능을 알고 있었고 결국 표준 라이브러리의 구조가 합리적인 시간에 C에서 구현할 수있는 맵과 문자열보다 성능이 우수하고 안정적 ​​일 것이라는 결론에 도달했습니다. C에서 링크 가능해야하는 요구 사항은 C ++ 코드에 C 인터페이스를 작성하여 쉽게 충족 할 수있었습니다.이 인터페이스는 불투명 한 유형으로 빠르게 수행되었습니다. C ++로 라이브러리를 다시 작성하는 것은 C로 작성하는 것보다 훨씬 빠르며 버그, 특히 메모리 누수가 발생하기 쉽습니다. 또한 플랫폼 별 구현을 사용하는 것보다 훨씬 쉬운 표준 라이브러리 스레딩 라이브러리를 사용할 수있었습니다. 결국 C ++로 라이브러리를 작성하면 성능 비용이 약간 낮아 큰 이점을 얻을 수 있다고 생각합니다. 아직 C ++ 버전을 벤치마킹하지는 않았지만 필자가 작성한 것보다 표준 라이브러리 데이터 구조를 사용하여 성능을 얻었을 수도 있습니다. C ++로 라이브러리를 작성하면 성능이 약간 낮을 때 큰 이점이 있다고 생각합니다. 아직 C ++ 버전을 벤치마킹하지는 않았지만 필자가 작성한 것보다 표준 라이브러리 데이터 구조를 사용하여 성능을 얻었을 수도 있습니다. C ++로 라이브러리를 작성하면 성능 비용이 적을 때 큰 이점이 있다고 생각합니다. 아직 C ++ 버전을 벤치마킹하지는 않았지만 필자가 작성한 것보다 표준 라이브러리 데이터 구조를 사용하여 성능을 얻었을 수도 있습니다.


9
최신 MSVC 지원은 실제로 C89입니다.
detly

4
@detly Visual Studio 2013에서는 대부분의 C99 기능이 지원됩니다 . 전폭적 인 지원은 아니지만 실제로는 C99를 작성하는 데 사용하는 것이 좋습니다.
congusbongus

4
@ danielu13-C가 C ++보다 성능 이점이 있다는 것을 정확히 어디서 들었습니까?
Ramhound

1
@ Sebastian-LaurenţiuPlesciuc 나는 그 링크가 실제로 도움이되지 않는다고 생각합니다. 첫 번째 질문은 거의 같은 질문 프로그래머 와 잘 맞을 수 있지만 링크와 같이 c 대신 c ++를 선호합니다. 귀하의 두 번째 링크의 경우, 그것은 단지 리누스 토 발드의 광란입니다. 나는 그가 c ++를 싫어하고 막대기로 만지지 않기를 좋아하지만 c ++에 대한 그의 열정은 객관적이지 않으며 개인적인 의견과 편견으로 가득 차 있으며 실제로 언어의 현실을 반영하지 않습니다. . 적어도 그것은 내 의견 이다.
user1942027 2014 년

1
@RaphaelMiedl 또한 이것이 2007 년에 작성된 것으로 언급 된 바 있는데, 꽤 오래 전에 C ++ 컴파일러와 C ++ 언어가 그 이후로 발전해 왔습니다. 그럼에도 불구하고, 어떤 언어를 사용할지는 프로그래머가 결정해야합니다.
Sebastian-Laurenţiu Plesciuc

답변:


89

사람들은 종종 C의 성능에 대해 추론 하기가 쉽기 때문에 C가 C ++보다 빠르다고 주장합니다 . C ++은 본질적으로 느리거나 빠르지는 않지만 특정 C ++ 코드는 숨겨진 성능 불이익을 가릴 수 있습니다. 예를 들어, 일부 C ++ 코드를 볼 때 즉시 보이지 않는 사본 및 암시 적 변환이있을 수 있습니다.

다음 진술을 보자.

foo->doSomething(a + 5, *c);

doSomething다음과 같은 서명이 있다고 가정 해 봅시다 .

void doSomething(int a, long b);

이제이 특정 진술의 가능한 성능 영향을 분석해 봅시다.

C에서는 그 의미가 분명합니다. foo구조체에 doSomething대한 포인터 일 수 있으며 함수에 대한 포인터 여야합니다. *c긴 참조를 해제하고 a + 5정수 추가입니다. 유일한 불확실성은 다음과 같은 유형에서 나옵니다 a. int가 아닌 경우 약간의 변환이 있습니다. 그러나 그 외에도이 단일 성명서의 성능 영향을 정량화하는 것은 쉽습니다.

이제 C ++로 바꾸자. 동일한 설명은 이제 매우 다른 성능 특성을 가질 수 있습니다.

  1. doSomething비가 상 멤버 함수 (저렴한), 가상 멤버 함수 (약간 더 비싸다) std::function, 람다 등일 foo수 있습니다 operator->. 따라서 호출 비용을 수량화하려면 및 doSomething의 정확한 특성을 알아야합니다 .foodoSomething
  2. a정수 또는 정수에 대한 참조 (추가 간접) 또는을 구현하는 클래스 유형일 수 있습니다 operator+(int). 연산자는 암시 적으로로 변환 가능한 다른 클래스 유형을 반환 할 수도 int있습니다. 다시 한 번, 성능 비용은 진술만으로는 분명하지 않습니다.
  3. c구현하는 클래스 유형일 수 있습니다 operator*(). 또한 long*등등에 대한 참조가 될 수 있습니다 .

당신은 그림을 얻는다. 때문에 C ++의 언어 기능에, 그것은 더 힘들어이 같은 추상화 추가 C. 지금에보다 하나의 명령문의 성능 비용을 정량화하는 것입니다 std::vector, std::string일반적으로 자신의 성능 특성을 가지고있는, C ++에서 사용하고 숨기기 동적 메모리 할당된다 ( @Ian의 답변도 참조하십시오).

결론은 다음과 같습니다. 일반적으로 C 또는 C ++를 사용하여 얻을 수있는 성능에는 차이가 없습니다. 그러나 실제로 성능이 중요한 코드의 경우 숨겨진 성능 저하 가능성이 적기 때문에 C를 선호하는 경우가 많습니다 .


1
훌륭한 답변. 이것이 내 대답에서 암시하는 것이지만 훨씬 더 잘 설명했습니다.
Ian Goldby 2014 년

4
이것은 실제로 받아 들여지는 대답이어야합니다. "C가 C ++보다 빠릅니다"와 같은 명령문이 존재하는 이유를 설명합니다. C는 C ++보다 빠르거나 느릴 수 있지만 일반적으로 특정 C 코드 조각이 왜 빠르거나 느린 지 알아내는 것이 훨씬 쉬워 일반적으로 최적화하기가 더 쉽습니다.
레오

이 훌륭한 답변 (+ 1)에서 아무것도 가져 가지 않지만 컴파일러는이 비교에서 사과와 오렌지가 될 수 있습니다. C와 C ++에 대해 동일한 코드를 생성하거나 생성하지 않을 수 있습니다. 물론 두 개의 컴파일러 또는 컴파일러 옵션에 대해서도 동일하게 말할 수 있으며 심지어 동일한 소스 언어 가정으로 물리적으로 동일한 프로그램을 컴파일하는 경우에도 마찬가지입니다.
JRobert

4
나는 대부분의 C ++ 런타임이 동등한 C 런타임에 비해 방대하다고 덧붙일 것입니다. 메모리 제한이있는 경우 중요합니다.
제임스 앤더슨

당신이 정말로 있다면 @JamesAnderson는 것을 에 메모리가 제한되어, 당신은 아마 모든 :)에서 런타임을 필요로하지 않습니다
나빈

30

C ++로 작성된 코드는 특정 유형의 작업에 대해 C보다 빠릅니다.

C ++를 선호하는 경우 C ++를 사용하십시오. 성능 문제는 소프트웨어의 알고리즘 결정과 비교할 때 중요하지 않습니다.


6
더 빠를 수 있지만 같은 이유로 더 빠를 수는 없습니다.
Rob

최적화 된 C보다 빠른 C ++로 작성된 최적화 된 코드의 예를 제공 할 수 있습니까?

1
@TomDworzanski : 한 가지 예는 템플릿을 사용하여 코드 경로에 대한 결정을 컴파일 타임에 결정하고 c로 작성된 경우 필요한 조건 및 분기가 아니라 최종 바이너리에서 하드 코딩 된 최종 코드로 처리 할 수 ​​있다는 것입니다. 인라인을 통한 함수 호출을 피하기 위해.
whatsisname

23

C ++의 디자인 원칙 중 하나는 사용하지 않는 기능에 대해서는 비용을 지불하지 않는다는 것입니다. 따라서 C ++로 코드를 작성하고 C에 존재하지 않는 기능을 피하면 결과 컴파일 된 코드는 성능과 동일해야합니다 (이를 측정해야 함).

예를 들어 구조체와 관련된 함수와 비교할 때 클래스를 사용하는 데 드는 비용은 무시할 수 있습니다. 가상 기능은 약간 더 비싸므로 성능을 측정하여 애플리케이션에 중요한지 여부를 확인해야합니다. 다른 C ++ 언어 기능도 마찬가지입니다.


3
가상 함수 디스패치 오버 헤드는 분해하고 가상으로 만드는 방법을 배제하지 않는 한 무시할 만합니다. vtables는 나머지 코드 및 데이터에 비해 작으며 vtable을 통한 인덱싱 된 분기는 각 루틴 호출에 몇 가지 시계를 추가합니다. 일상적인 호출은 모두 수백에서 수백만 개의 시계에 이르기까지, vtable 브랜치는 소음 층에 묻힐 것입니다.
John R. Strohm 1

6
Structs는 C ++의 클래스입니다.
rightfold

2
@rightfold : 물론입니다. 그러나 this포인터 언어 기능 을 사용하지 않고도 구조체의 포인터를 전달하는 C ++ 코드를 작성할 수 있습니다 . 그게 내가 말하는 전부 야
Greg Hewgill

4
@ John 실제 비용은 간접적 인 것이 아니지만 (일부 프로세서 프리 페치와 약간의 문제가있을 것이라고 확신하지만) 가상 함수를 (최소한 C ++로) 인라인 할 수 없다는 사실은 많은 가능성을 허용하지 않습니다. 최적화. 그렇습니다. 성능에 큰 영향을 줄 수 있습니다.
Voo

2
@Voo 공정하게 말하면 동등한 C 코드 (런타임 다형성을 수동으로 에뮬레이트하는 코드)에 대해서도 마찬가지입니다. 가장 큰 차이점은 컴파일러가 해당 함수가 C ++로 인라인 될 수 있는지 판단하기가 더 쉽다는 것입니다.
Thomas Eding

14

높은 수준의 언어가 때때로 느린 이유 중 하나는 낮은 수준의 언어보다 훨씬 많은 메모리 관리 기능을 숨길 수 있기 때문입니다.

낮은 수준의 세부 정보를 추상화하는 모든 언어 (또는 라이브러리, API 등)는 비용이 많이 드는 작업을 숨길 수 있습니다. 예를 들어, 일부 언어에서는 문자열에서 후행 공백을 트리밍하면 메모리 할당과 문자열 복사본이 생성됩니다. 특히 메모리 할당 및 복사는 타이트한 루프에서 반복적으로 발생하는 경우 비용이 많이들 수 있습니다.

C로 이런 종류의 코드를 작성했다면 명백히 명백 할 것입니다. C ++에서는 할당 및 복사가 클래스로 추상화 될 수 있기 때문에 가능하지 않습니다. 심지어 순진한 오버로드 된 연산자 나 복사 생성자 뒤에 숨겨져있을 수도 있습니다.

원하는 경우 C ++을 사용하십시오. 그러나 그 아래에 무엇이 있는지 모를 때 추상화의 편의로 보지 마십시오.

물론 프로파일 러를 사용하여 실제로 코드 속도를 늦추는 것이 무엇인지 알아보십시오.


5

가치있는 것을 위해 강화 된 기능 세트를 위해 라이브러리를 C ++ 11로 작성하는 경향이 있습니다. 공유 포인터, 예외, 일반 프로그래밍 및 기타 C ++ 전용 기능과 같은 기능을 활용할 수있는 것이 좋습니다. C ++ 11을 좋아합니다. 관심있는 모든 플랫폼에서 좋은 비트가 지원된다는 것을 알았습니다. Visual Studio 2013에는 많은 핵심 언어 기능과 라이브러리 구현이 준비되어 있으며 나머지를 추가하기 위해 노력하고 있습니다. 아시다시피 Clang과 GCC는 전체 기능 세트도 지원합니다.

그 말에 따르면, 최근에는 도서관 개발과 관련하여 실제로 귀하의 검색어와 직접 관련이 있다고 생각하는 훌륭한 전략에 대해 읽었습니다. 이 기사의 제목은 "C ++ 예외와 함께 잘 작동하는 AC 오류 처리 스타일"입니다. Stefanu Du Toit는이 전략을 "모래 시계"패턴이라고합니다. 기사의 첫 번째 단락 :

필자는 "모래 시계"패턴을 사용하여 많은 라이브러리 코드를 작성했습니다. 라이브러리 (일반적으로 C ++를 사용하여)를 구현하고 라이브러리의 유일한 진입 점이되는 C API로 래핑합니다. 그런 다음 C API를 C ++ 또는 다른 언어로 래핑하여 풍부한 추상화와 편리한 구문을 제공하십시오. 기본 크로스 플랫폼 코드와 관련하여 C API는 비교할 수없는 ABI 안정성과 FFI를 통한 다른 언어로의 이식성을 제공합니다. 심지어 API를 다양한 FFI로 이식 할 수있는 C의 하위 집합으로 제한하고 라이브러리가 내부 데이터 구조의 누출을 막는 것을 방지합니다. 향후 블로그 게시물에서 더 많은 내용을 기대합니다.


이제 주요 관심사 인 성능을 해결하십시오.

나는 다른 많은 답변과 마찬가지로 두 언어로 코드를 작성하는 것이 성능면에서 잘 작동한다고 제안합니다. 개인적 관점에서 볼 때 언어 기능으로 인해 C ++로 올바른 코드를 작성하는 것이 더 쉽다는 것을 알지만 개인적 선호가 있다고 생각합니다. 어느 쪽이든, 컴파일러는 실제로 똑똑하고 어쨌든 더 나은 코드를 작성하는 경향이 있습니다. 즉, 컴파일러는 가능한 것보다 코드를 더 잘 최적화 할 것입니다.

나는 많은 프로그래머들이 이것을 알고 있지만, 가장 먼저해야 할 일은 코드를 작성한 다음 프로파일 링하고 프로파일 러가 제안하는 위치를 최적화하는 것입니다. 병목 현상이 발생한 위치를 확인할 수 있으면 기능을 생성 한 다음 최적화하는 데 시간이 훨씬 더 많이 걸립니다.


이제 언어 기능 및 최적화가 실제로 유리하게 작동하는 방법에 대한 재미있는 내용을 읽으십시오.

std :: unique_ptr에는 오버 헤드가 없습니다.

constexp는 컴파일 타임 계산을 허용합니다

이동 의미론은 불필요한 임시 객체를 방지합니다.


std::unique_ptr has zero overhead예외로 인해 스택이 풀리면 생성자가 호출되어야하기 때문에 (기술적으로 말하면) 사실 일 수 없습니다. 원시 포인터는이 오버 헤드가 없으며 코드가 throw되지 않을 경우 여전히 정확합니다. 컴파일러는 일반적인 경우 이것을 증명할 수 없습니다.
Thomas Eding

2
@ThomasEding 예외없는 코드와 관련하여 크기와 런타임 오버 헤드를 언급하고있었습니다. 내가 틀렸다면 수정하지만 예외가 발생하지 않을 때 런타임 오버 헤드가 발생하지 않아 실행시 예외가 전파 될 수있는 실행 모델이 있습니다. 그럼에도 불구하고 언제 unique_ptr? 의 생성자에서 예외가 발생할 수 있습니까? 선언 noexcept되어 있으므로 최소한 모든 예외를 처리하지만 처음에는 어떤 유형의 예외가 발생할 수 있는지 상상할 수 없습니다.
vmrob

vmrob : 용서해주세요 ... "constructor"대신 "destructor"를 쓰려고했습니다. 또한 "아마도 던지지 않을 것"이라고 쓰려고했습니다. 여덟!
Thomas Eding

2
@ThomasEding 아시다시피, 소멸자가 예외를 던지더라도 중요하지 않다고 생각합니다. 소멸자가 새로운 예외를 도입하지 않는 한 여전히 오버 헤드 파괴는 없습니다. 또한 전체 소멸자가 최적화 된 단일 삭제 / 무료 호출에 인라인된다고 생각합니다.
vmrob

4

C ++과 C의 성능 차이는 엄밀히 말해서 언어의 어떤 것이 아니라 당신이하고 싶은 유혹에 의한 것입니다. 신용 카드 대 현금과 같습니다. 그것은 당신이 더 많은 지출을하지는 않지만, 당신이 매우 징계되지 않는 한 어쨌든합니다.

다음 은 C ++로 작성된 프로그램 의 예 입니다. 언어에 관계없이 적극적인 성능 조정 방법을 알아야합니다. 이 비디오에 표시된 것처럼 내가 사용하는 방법은 임의의 일시 중지입니다.

C ++이 당신에게 해야하는 많은 종류의 과도한 메모리 관리, 알림 스타일 프로그래밍, 프로그램 카운터를 멀티 레이어 추상화 라이브러리 (@Ian이 말했듯이)에 신뢰, 느림 숨기기 숨기기 등이 있습니다.


2

두 언어에서 동일한 작업을 수행하는 경우 C는 C ++에 비해 성능 이점이 없습니다. 괜찮은 C 프로그래머가 작성한 오래된 C 코드를 가져 와서 유효하고 동등한 C ++ 코드로 바꿀 수 있습니다.이 코드는 빠른 속도로 실행됩니다. 그러나 대부분의 사람들은 그렇지 않습니다).

(1) 표준 C ++ 라이브러리를 사용하여 라이브러리를 사용하지 않고 훨씬 빠르고 쉽게 수행 할 수있는 작업을 수행하거나 (2) 표준 C ++ 라이브러리를 사용하는 경우 C ++의 성능이 느리거나 빨라질 수 있습니다. 나쁜 C에서 라이브러리를 다시 구현하는 것보다 훨씬 쉽고 빠르게 할 수 있습니다.


1
이것은 6 개의 이전 답변에서 설명 된 것보다 실질적인 것을 제공하지 않는 것 같습니다
gnat

이 답변에는 아무도 언급하지 않은 중요한 점이 언급되어 있습니다. 언뜻보기에 C ++은 C의 슈퍼 세트 인 것처럼 보이므로 빠른 C 구현을 작성할 수 있으면 동등한 C ++ 구현을 작성할 수 있어야합니다. 그러나 C99는 의도하지 않은 포인터 앨리어싱을 피할 수있는 제한 키워드를 지원합니다. C ++은 그런 지원을하지 않습니다. 포인터 별칭 지정을 피하는 기능은 고성능 응용 프로그램에 유용한 Fortran의 중요한 기능입니다. 비슷한 도메인에서 C ++보다 C99에서 더 나은 성능을 얻는 것이 가능할 것으로 기대합니다.
user27539
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.