2014-09-02 1 views
2

그의 FAQ에서 Bjarne Stroustrup은 gcc -O2로 컴파일 할 때 C와 C++를 사용하는 hello world의 파일 크기가 동일하다고 말합니다.C++ Hello World 바이너리가 동등한 C 바이너리보다 큰 이유는 무엇입니까?

참고 :이 시도하기로 결정 http://www.stroustrup.com/bs_faq.html#Hello-world

, 여기에 C 버전입니다 :

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    printf("Hello world!\n"); 
    return 0; 
} 

그리고 여기에 여기에 내가 컴파일하고 크기를 C++ 버전

#include <iostream> 

int main(int argc, char* argv[]) 
{ 
    std::cout << "Hello world!\n"; 
    return 0; 
} 

입니다 다른 :

[email protected]:~/hello$ ls 
hello.c hello.cpp 
[email protected]:~/hello$ gcc -O2 hello.c -o c.out 
[email protected]:~/hello$ g++ -O2 hello.cpp -o cpp.out 
[email protected]:~/hello$ ls -l 
total 32 
-rwxr-xr-x 1 r00t r00t 8559 Sep 1 18:00 c.out 
-rwxr-xr-x 1 r00t r00t 8938 Sep 1 18:01 cpp.out 
-rw-r--r-- 1 r00t r00t 95 Sep 1 17:59 hello.c 
-rw-r--r-- 1 r00t r00t 117 Sep 1 17:59 hello.cpp 
[email protected]:~/hello$ size c.out cpp.out 
    text data  bss  dec  hex filename 
    1191  560  8 1759  6df c.out 
    1865  608  280 2753  ac1 cpp.out 

std::endl\n으로 바꿨고 이진을 더 작게 만들었습니다. 나는이 단순한 것이 인라인 될 것이라고 생각했다. 그리고 dissapointed하지 않았다.

최적화 된 어셈블리에는 수백 줄의 어셈블리 출력이 있습니까? sys_write를 사용하여 5 개의 어셈블리 명령어를 사용하여 hello world를 작성할 수 있습니다. 모든 추가 작업에는 어떤 것이 있습니까? 왜 C가 스택에 많은 여분을 설치하려고합니까? 어셈블리의 50 바이트와 C의 8kb와 같은 이유는 무엇입니까?

+9

아니요, 그는 그런 말하지 않았다. 그는 "2004 년에 유닉스에서 gcc -O2를 사용하여 테스트했고 두 버전 (iostreams 및 stdio)은 동일한 크기를 산출했습니다."* –

+4

구체적으로 질문은 무엇입니까? 또한 Bjarne이이 사실에 대해 거짓말을했다는 주장은 다소 강하다고 생각합니다. 이전 시스템의 구형 컴파일러에서 바이너리가 동일한 크기를 가질 수도 있습니다 (최신 시스템이 아닐지라도 이것이 사실이 아닙니다). – templatetypedef

+0

이제 심볼을 제거하십시오 ... –

답변

4

그는 반올림 오류로 반 킬로바이트를 처리하고 있다고 생각합니다. 두 파일 모두 "9 킬로바이트"이며 일반적인 파일 브라우저에서 볼 수 있습니다. 후드에서 C와 C++ 라이브러리가 상당히 다르기 때문에 정확히 동일하지는 않습니다. 디스어셈블러에 대해 이미 잘 알고 있다면 차이점에 대한 세부 정보를 직접 볼 수 있습니다.

"추가 내용"은 표준 라이브러리 shlib에서 심볼을 가져오고 C++ 예외를 처리하기위한 것입니다. 이상하게도 GCC 컴파일 된 C 실행 파일의 대부분은 C++ 예외 처리 테이블에 의해 사용됩니다. GCC를 사용하여 스트립하는 방법을 알아 내지 못했습니다.

endl는 인라인,하지만 인라인되지 않은 스트림의 \n 문자를 인쇄 플러시 호출을 포함합니다. 크기의 차이는 표준 라이브러리에서 가져 오는 것이기 때문입니다.

실제로 동적으로로드 된 라이브러리가있는 모든 시스템에서 개별 킬로바이트는 거의 중요하지 않습니다. 임베디드 시스템과 같은 자체 포함 된 코드는 사용하는 표준 라이브러리 기능을 포함해야하며 C++ 표준 라이브러리는 C 코드보다 두꺼운 경향이 있습니다 (특히 <iostream><stdio.h>).

+0

_ "나는 GCC를 사용하여 그들을 제거하는 방법을 찾지 못했습니다."_'-fno-exceptions'는 대개 예외 사용을 막습니다. 예외 처리를 위해 terminate (terminate_handler 등) 코드를 제공하는'stdlibC++ '에서 오버라이드 할 약한 함수가있다. –

+1

@ πάνταῥεῖ 물론 제가 시도한 첫 번째 문제입니다 : v). 네가 일하는 것을 찾으면 알려줘. 이 문제는 예외를 생성하지 않고 예외를 사용하는 함수에 대한 호출을 지원합니다. – Potatoswatter

+0

필자는 동료 작업을 점검해야 할 것이며, 언급 된 약한 기능을 무시함으로써 표준 catch되지 않은 예외 처리 코드를 생략하는 트릭을 수행했습니다. 나는 지금 정확한 이름을 기억하지 못한다. –

7

쉽게 오해 할 수있는 정보가 혼합되어 있습니다. 8559 및 8938 바이트 파일 크기는 대부분 최소한의 디버깅 목적을 위해 기호 이름 및 기타 정보가 포함 된 헤더이므로 대부분 의미가 없습니다. 다소 의미있는 숫자는 나중에 추가 size(1) 출력 :

[email protected]:~/hello$ size c.out cpp.out 
    text data  bss  dec  hex filename 
    1191  560  8 1759  6df c.out 
    1865  608  280 2753  ac1 cpp.out 

당신은 size-A 옵션을 사용하여 더 자세한 분석을 얻을 수 있지만, 짧은에, 여기에 차이는 매우 사소한입니다.

재미있는 점은 Bjarne Stroustrup이 정적 링크인지 동적 링크인지에 대해서는 언급하지 않았다는 것입니다.귀하의 경우 두 프로그램 모두 동적 연결이므로 크기 차이는 stdio 또는 iostream의 실제 크기 비용과 아무 관련이 없습니다. 당신은 단지 호출 코드의 비용을 측정하거나 C++에 대한 예외 처리 지원의 기본 오버 헤드를 (다른 주석/응답을 기반으로하여) 측정합니다. 이제 컴파일러가 operator<<의 오버로드 된 버전을 정확히 볼 수 있고 불필요한 코드를 최적화 할 수 있기 때문에 정적 링크 된 C++ iostream 기반 안녕하세요도 printf 기반의 것보다 훨씬 작을 수 있다는 공통적 인 주장이 있습니다. 값 비싼 부동 소수점 인쇄). 반면에 printf의 형식 문자열 사용은 일반적으로 어려우며 일반적으로 불가능합니다. 그러나 정적 링크 된 iostream 기반 hello 프로그램은 C에서 printf 기반의 것보다 훨씬 작을 정도로 가까이에있을 수있는 C++ 구현을 본 적이 없습니다.