IT이야기

C++에서는 안 먹는 거 계산하나요?

cyworld 2022. 7. 25. 22:46
반응형

C++에서는 안 먹는 거 계산하나요?

C 및 C++의 다음 hello 월드 예를 살펴보겠습니다.

main.c

#include <stdio.h>

int main()
{
    printf("Hello world\n");
    return 0;
}

main.cpp

#include <iostream>

int main()
{
    std::cout<<"Hello world"<<std::endl;
    return 0;
}

대한 때, Godbolt)밖에 되지 않습니다.gcc -O3

.LC0:
        .string "Hello world"
main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:.LC0
        call    puts
        xor     eax, eax
        add     rsp, 8
        ret

, C 행C++ 코드)입니다.g++ -O3

.LC0:
        .string "Hello world"
main:
        sub     rsp, 8
        mov     edx, 11
        mov     esi, OFFSET FLAT:.LC0
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
        xor     eax, eax
        add     rsp, 8
        ret
_GLOBAL__sub_I_main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:_ZStL8__ioinit
        call    std::ios_base::Init::Init() [complete object constructor]
        mov     edx, OFFSET FLAT:__dso_handle
        mov     esi, OFFSET FLAT:_ZStL8__ioinit
        mov     edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
        add     rsp, 8
        jmp     __cxa_atexit

... 훨씬 더 큽니다.

C++에서는 당신이 먹는 것에 대해 돈을 낸다는 것은 유명하다.그럼, 이 경우엔 제가 뭘 지불하면 될까요?

그럼, 이 경우엔 제가 뭘 지불하면 될까요?

std::cout printf로케일, 스테이트풀 포맷 플래그 등을 지원합니다.

std::printf ★★★★★★★★★★★★★★★★★」std::puts 에서볼 수 . - 에서 볼 수 있습니다.<cstdio>.


C++에서는 당신이 먹는 것에 대해 돈을 낸다는 것은 유명하다.

또, C++!= C++ Standard Library도 확실히 하고 싶습니다.Standard Library는 범용적이고 "충분히 빠른" 것으로 여겨지지만, 필요한 것을 전문적으로 구현하는 것보다 더 느린 경우가 많습니다.

C 비용을하지 않고 수 、 C++ ) 。virtual collection), " garbage collection" 입니다.

C++는 C++로 하다.하고 있습니다.printf ★★★★★★★★★★★★★★★★★」std::cout다양한 기능(로케일, 스테이트 풀 포맷 등)을 사용할 수 있습니다.

비교를 위해 다음 코드를 사용해 보십시오.Godbolt는 두 파일에 대해 동일한 어셈블리를 생성합니다(gcc 8.2, -O3로 테스트됨).

main.c:

#include <stdio.h>

int main()
{
    int arr[6] = {1, 2, 3, 4, 5, 6};
    for (int i = 0; i < 6; ++i)
    {
        printf("%d\n", arr[i]);
    }
    return 0;
}

main.cpp:

#include <array>
#include <cstdio>

int main()
{
    std::array<int, 6> arr {1, 2, 3, 4, 5, 6};
    for (auto x : arr)
    {
        std::printf("%d\n", x);
    }
}

귀사의 목록은 실제로 사과와 오렌지를 비교하고 있지만, 대부분의 다른 답변에 내포된 이유 때문이 아닙니다.

코드의 실제 기능을 확인합니다.

C:

  • "Hello world\n"

C++:

  • 을 잇다"Hello world"std::cout
  • 을 흐르다std::endl를 조작하여 조작하다std::cout

당신의 C++코드는 두 배의 작업을 하고 있는 것 같습니다.공정한 비교를 위해 다음을 결합해야 합니다.

#include <iostream>

int main()
{
    std::cout<<"Hello world\n";
    return 0;
}

가 붙었다main다고 하다

main:
        sub     rsp, 8
        mov     esi, OFFSET FLAT:.LC0
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
        xor     eax, eax
        add     rsp, 8
        ret

실제로 C 코드와 C++ 코드를 한 줄씩 비교할 수 있으며 차이는 거의 없습니다.

sub     rsp, 8                      sub     rsp, 8
mov     edi, OFFSET FLAT:.LC0   |   mov     esi, OFFSET FLAT:.LC0
                                >   mov     edi, OFFSET FLAT:_ZSt4cout
call    puts                    |   call    std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
xor     eax, eax                    xor     eax, eax
add     rsp, 8                      add     rsp, 8
ret                                 ret

진짜 C++에서는 C++라고 것입니다.operator <<의 인수2개의 인수))를 합니다.std::cout스트링)을 클릭합니다.더 C 더 c c C eqiga를 사용함으로써 그할 수 .fprintf스트림을 지정하는 첫 번째 인수도 있습니다.

조립 ._GLOBAL__sub_I_mainC++용으로 생성되지만 C용으로 생성되지는 않습니다.이 어셈블리 목록에서 볼 수 있는 유일한 실제 오버헤드입니다(물론 두 언어 모두 더 많은 보이지 않는 오버헤드가 있습니다).이 코드는 C++ 프로그램 시작 시 일부 C++ 표준 라이브러리 함수의 일회성 설정을 수행합니다.

했듯이 이 두 는 이 의 어셈블리 수 main모든 무거운 리프팅이 뒤에서 이루어지기 때문에 기능합니다.

비용을 지불하고 무거운 라이브러리를 호출합니다(콘솔에 인쇄하는 것만큼 무겁지 않습니다). 때 '초기화'를 .ostream숨겨진 저장소가 있습니다.아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.std::endl은 '의미 없다'의 .\n . 。iostream라이브러리는 많은 설정을 조정하여 프로그래머가 아닌 프로세서에 부담을 주는 데 도움이 됩니다.이것은 당신이 지불하는 것입니다.

코드를 확인합니다.

.LC0:
        .string "Hello world"
main:

ostream 객체 초기화 + cout

    sub     rsp, 8
    mov     edx, 11
    mov     esi, OFFSET FLAT:.LC0
    mov     edi, OFFSET FLAT:_ZSt4cout
    call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)

" "cout 한 번 새

    mov     edi, OFFSET FLAT:_ZSt4cout
    call    std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
    xor     eax, eax
    add     rsp, 8
    ret

정적 스토리지 초기화:

_GLOBAL__sub_I_main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:_ZStL8__ioinit
        call    std::ios_base::Init::Init() [complete object constructor]
        mov     edx, OFFSET FLAT:__dso_handle
        mov     esi, OFFSET FLAT:_ZStL8__ioinit
        mov     edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
        add     rsp, 8
        jmp     __cxa_atexit

또한 언어와 도서관을 구분하는 것도 필수적입니다.

그나저나 이건 이야기의 일부일 뿐이야호출하는 함수에 무엇이 적혀 있는지 알 수 없습니다.

C++에서는 당신이 먹는 것에 대해 돈을 낸다는 것은 유명하다.그럼, 이 경우엔 제가 뭘 지불하면 될까요?

당신하세요.std::cout는 말은 "의 가격을 뜻이 먹은 만큼만 계산한다'는 말은 '항상 최고의 가격을 받는다'는 뜻이 아닙니다. sure sure죠 sure sure sure.printf더 저렴합니다.라고 할 수 std::cout보다 안전하고 다용도성이 높기 때문에, 코스트가 큰 것은 정당화됩니다(비용은 비싸지만, 가치는 높아집니다).하지만 요점을 놓치고 있습니다.★★★★★★★★★★★★★★★★★★★★★★는 사용하지 않습니다printf , 을합니다.std::coutstd::cout돈요.printf.

좋은 예로 가상 기능을 들 수 있습니다.가상 기능에는 몇 가지 런타임 비용과 공간 요건이 있지만 실제로 사용하는 경우에만 필요합니다.가상 기능을 사용하지 않으면 아무것도 지불하지 않습니다.

몇 마디

  1. C++ 코드가 더 많은 어셈블리 명령으로 평가되더라도 여전히 소수의 명령일 뿐이며 실제 I/O 작업에 따라 성능 오버헤드가 줄어들 가능성이 높습니다.

  2. 사실 'C++에서 돈 내고 먹는 것'보다 더 좋을 때도 있어요.예를 들어, 컴파일러는 가상 함수 호출이 어떤 상황에서는 필요하지 않다고 추론하고, 그것을 비가상 호출로 변환할 수 있습니다.즉, 가상 기능을 무료로 사용할 수 있습니다.대단하지 않아요?

여기 몇 가지 유효한 답이 있는데, 자세한 내용은 좀 더 자세히 알아보겠습니다.

이 텍스트의 벽을 모두 통과하고 싶지 않은 경우 아래 요약으로 이동하여 주요 질문에 대한 답변을 얻으십시오.


추상화

그럼, 이 경우엔 제가 뭘 지불하면 될까요?

추상화에 대한 대가를 치르고 있습니다.보다 간단하고 인간 친화적인 코드를 작성할 수 있는 것은 대가가 따른다.객체 지향 언어인 C++에서는 거의 모든 것이 객체입니다.어떤 물체를 사용할 때, 후드 아래에서 항상 세 가지 주요 현상이 발생합니다.

  1. 객체 생성. 기본적으로 객체 자체와 데이터에 대한 메모리 할당입니다.
  2. 은 일부의 「Initialization」(「Initialization」)에)init() 은 보통에서 가장 .보통 메모리 할당은 이 단계에서 가장 먼저 후드 아래에서 이루어집니다.
  3. 오브젝트 파괴(항상 그렇지는 않습니다.

코드에는 없지만 오브젝트를 사용할 때마다 위의 세 가지 모든 것이 어떻게든 일어나야 합니다.모든 작업을 수동으로 수행한다면 코드가 훨씬 길어질 것입니다.

이제 오버헤드를 추가하지 않고도 효율적으로 추상화를 만들 수 있습니다. 메서드 인라인 및 기타 기술을 컴파일러와 프로그래머가 모두 사용하여 추상화의 오버헤드를 제거할 수 있지만, 이 경우는 그렇지 않습니다.

C++에서는 실제로 어떤 일이 일어나고 있습니까?

여기 있습니다. 분해해 주세요.

  1. std::ios_base클래스가 초기화됩니다.I/O를 사용하다
  2. std::cout이치노
  3. 되었습니다.std::__ostream_insert 알 수 는 (이름으로 알 수)의 입니다.std::cout ( ( )<<operator합니다.
  4. cout::endl에도 전달된다.std::__ostream_insert.
  5. __std_dso_handle__cxa_atexit이 기능은 프로그램을 종료하기 전에 "청소"를 담당하는 글로벌 기능입니다. __std_dso_handle그 자체를 이 함수에 의해 호출하여 나머지 글로벌오브젝트의 할당을 해제하고 파기합니다.

C ==를 사용하면 아무런 비용도 지불하지 않습니다.

C 코드에서는, 다음의 몇개의 스텝이 발생하고 있습니다.

  1. 되었습니다.puts the를 edi등록하세요.
  2. puts출됩니니다다

오브젝트가 어디에도 없기 때문에 초기화/파괴할 필요가 없습니다.

그렇다고 해서 C에 있는 어떤 물건에 대해서도 "지불"을 하지 않는 것은 아닙니다.C 표준 라이브러리의 초기화와 동적 해상도에 대한 비용을 여전히 지불하고 있습니다.printf는 「」)puts포맷 문자열이 필요 없기 때문에 컴파일러에 의해 최적화되어 있습니다).

이 프로그램을 순수한 어셈블리로 작성하면 다음과 같이 됩니다.

jmp start

msg db "Hello world\n"

start:
    mov rdi, 1
    mov rsi, offset msg
    mov rdx, 11
    mov rax, 1          ; write
    syscall
    xor rdi, rdi
    mov rax, 60         ; exit
    syscall

으로는 " " " " " " " " 이 됩니다.write syscall에 이어exit시스템같은 일을 할 수 있는 최소한의 방법일 겁니다


정리하면

C는 훨씬 베어본이며 필요한 최소한의 기능만 갖추고 있으며 기본적으로 사용자가 원하는 모든 기능을 완벽하게 최적화 및 맞춤화할 수 있습니다.프로세서에 레지스터에 문자열을 로드하도록 지시한 후 라이브러리 함수를 호출하여 해당 문자열을 사용합니다.반면에 C++는 훨씬복잡하고 추상적이다.이것은 복잡한 코드를 작성할 때 큰 이점을 가지고 있고, 쓰기 쉽고 인간 친화적인 코드를 만들 수 있지만, 분명히 대가가 따른다.C++는 이러한 기본 작업을 수행하는 데 필요한 것보다 더 많은 것을 제공하기 때문에 C++와 비교할 경우 항상 C++의 성능에는 단점이 있습니다.

주요 질문에 대한 답변:

안 먹는 거 계산해요?

이 특정한 경우, .C++가 C보다 더 많은 것을 제공해야 하는 것은 아닙니다만, 그것은 C++가 당신에게 도움이 될 만한 단순한 코드 조각이 없기 때문입니다.C++는 매우 간단하기 때문에, C++는 전혀 필요 없습니다.


아, 그리고 한 가지만 더!

C++의 장점은 매우 단순하고 작은 프로그램을 작성했기 때문에 언뜻 보기에는 분명해 보이지 않을 수 있지만 조금 더 복잡한 예를 들어 차이점을 확인하십시오(두 프로그램 모두 동일한 작업을 수행합니다).

C:

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    return *(int*)a - *(int*)b;
}

int main(void) {
    int i, n, *arr;

    printf("How many integers do you want to input? ");
    scanf("%d", &n);

    arr = malloc(sizeof(int) * n);

    for (i = 0; i < n; i++) {
        printf("Index %d: ", i);
        scanf("%d", &arr[i]);
    }

    qsort(arr, n, sizeof(int), cmp)

    puts("Here are your numbers, ordered:");

    for (i = 0; i < n; i++)
        printf("%d\n", arr[i]);

    free(arr);

    return 0;
}

C++:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(void) {
    int n;

    cout << "How many integers do you want to input? ";
    cin >> n;

    vector<int> vec(n);

    for (int i = 0; i < vec.size(); i++) {
        cout << "Index " << i << ": ";
        cin >> vec[i];
    }

    sort(vec.begin(), vec.end());

    cout << "Here are your numbers:" << endl;

    for (int item : vec)
        cout << item << endl;

    return 0;
}

내가 무슨 말을 하는지 잘 알기를 바랍니다., 에서는, 「C」, 「C」, 「C」를 사용해 를 보다 낮은 레벨로 것에 .malloc ★★★★★★★★★★★★★★★★★」free색인 및 크기에 더욱 주의를 기울여야 하는 방법, 입력 및 인쇄 시 매우 구체적으로 설명해야 하는 방법 등입니다.

printf 어셈블리 리스트는 printf가 아니라 puts(컴파일러 최적화 종류)를 위한 것입니다.; printf는 입력보다 훨씬 복잡합니다.잊지 마세요!

우선 몇 가지 오해가 있습니다.첫째, C++ 프로그램은 22개의 명령어를 생성하는 이 아니라 22,000개의 명령어에 가깝습니다(모자에서 그 숫자를 꺼냈지만 대략적인 수준입니다).또, C코드도 9개의 명령이 되는 것은 아닙니다.당신이 보는 건 저것뿐이에요.

C코드는 보이지 않는 많은 작업을 수행한 후 CRT에서 함수를 호출하여(보통 공유 lib로 존재하지는 않지만) 반환값을 체크하지 않고 오류를 처리하지 않고 구제합니다.컴파일러와 최적화 설정에 따라서는 실제로 호출조차 할 수 없습니다.printfputs아니면 더 원시적인 것이거나.
같은 함수를 같은 방법으로 호출했을 경우, C++에서도 같은 프로그램(일부 보이지 않는 초기화 함수 제외)을 거의 쓸 수 있습니다.초정확하게 하고 는, 에 「초정확하게」, 「초정확하게」를 std::.

대응하는 C++ 코드는 실제로는 전혀 동일하지 않습니다.★★★★★★★★의 전체는<iostream>그것은 작은 프로그램들을 위해 엄청난 오버헤드를 추가하는 뚱뚱하고 못생긴 돼지인 것으로 잘 알려져 있다. 다소 공평한 해석은 그것이 여러분이 보지 못하고 그저 효과가 있는 많은 것들을 한다는 것이다.다양한 번호 형식이나 로케일 등 임의의 형식의 마법적인 포맷, 버퍼링, 적절한 에러 처리 등, 거의 모든 랜덤한 포맷에 한정되지 않습니다.에러 처리?네, 문자열 출력은 실제로 실패할 수 있습니다.C 프로그램과 달리 C++ 프로그램은 이를 무시하지 않습니다.무엇을 생각하면std::ostream아무도 모르게 후드 아래에서 작동하는데, 사실 꽤 가볍습니다.열정적인 스트림 구문을 싫어하기 때문에 사용하는 것은 아닙니다.하지만 그래도 이게 뭘 하는지는 생각해보면 꽤 멋져요.

하지만 C++는 전체적으로 C만큼 효율적이지 않습니다.같은 일이 아니고 같은 일을 하고 있지 않기 때문에 효율적일 수 없습니다.C++는 예외(및 예외 생성, 처리 또는 장애 발생 코드)를 생성하고 C가 제공하지 않는 보증을 제공합니다.물론 C++ 프로그램은 조금 더 커야 합니다.그러나 큰 그림에서 이것은 어떤 식으로든 문제가 되지 않는다.반대로 실제 프로그램에서는 C++가 더 나은 성능을 발휘하는 경우가 드물지 않습니다. 어떤 이유로든 C++가 더 나은 최적화를 가능하게 하는 것 같기 때문입니다.이유를 묻지 마세요. 저도 몰라요.

fire-and-for-for-the-best가 아닌 올바른 C 코드를 쓰는 경우(즉, 실제로 오류를 확인하고 오류가 있는 경우 프로그램이 올바르게 동작함)에는 차이가 거의 없습니다.

당신은 실수에 대한 대가를 치르고 있어요.컴파일러가 포맷 문자열을 체크하기에 충분하지 않은 80년대에 연산자 오버로드는 IO 중에 일종의 형식 안전성을 강제하는 좋은 방법으로 여겨졌다.그러나 배너 기능은 모두 처음부터 제대로 구현되지 않았거나 개념적으로 파산했습니다.

<iomanip>

C++ stream io api의 가장 혐오스러운 부분은 이 포맷헤더 라이브러리의 존재입니다.스테이트풀하고 추악하며 오류가 발생하기 쉬운 것 외에 스트림에 포맷을 결합합니다.

8자리 0으로 채워진 16진수 int 뒤에 소수점 3자리가 있는 두 배가 이어지는 행을 인쇄한다고 가정합니다.★★★★★★★★★★★★★★★★ <cstdio>간결한 형식의 문자열을 읽을 수 있습니다.★★★★★★★★★★★★★★★★ <ostream>이전 상태를 저장하고, 정렬을 오른쪽으로 설정하고, 채우기 문자를 설정하고, 채우기 폭을 설정하고, 기준을 16진수로 설정하고, 정수를 출력하고, 저장된 상태를 복원하고(정수 포맷으로 인해 플로트 포맷이 오염됩니다), 공간을 출력하고, 표기를 고정으로 설정하고, 정밀도를 설정하고, 이중 및 새 행을 출력하고, 이전 포맷을 복원해야 합니다.

// <cstdio>
std::printf( "%08x %.3lf\n", ival, fval );

// <ostream> & <iomanip>
std::ios old_fmt {nullptr};
old_fmt.copyfmt (std::cout);
std::cout << std::right << std::setfill('0') << std::setw(8) << std::hex << ival;
std::cout.copyfmt (old_fmt);
std::cout << " " << std::fixed << std::setprecision(3) << fval << "\n";
std::cout.copyfmt (old_fmt);

연산자 오버로드

<iostream>연산자 오버로드를 사용하지 않는 방법에 대한 포스터입니다.

std::cout << 2 << 3 && 0 << 5;

성능

std::cout 배 느리다printf()만연한 기능성염과 가상 디스패치는 타격을 입습니다.

스레드 안전성

다.<cstdio> ★★★★★★★★★★★★★★★★★」<iostream>는 모든 함수 호출이 원자성이라는 점에서 스레드 세이프입니다.렇지 but but , but 。printf()한 통화당 더 많은 작업을 수행할 수 있습니다. the the the the the with with with with with with with with with 를 사용하여 다음 프로그램을 실행하면<cstdio>사항으로는 션, 음, 음, 음, 음, 음, 음, 음, 음, 음, option, option, option, option, option, option, option, option, optionf를 . . . . . . .를 사용하는 <iostream>멀티코어 머신에서는 다른 것을 볼 수 있습니다.

// g++ -Wall -Wextra -Wpedantic -pthread -std=c++17 cout.test.cpp

#define USE_STREAM 1
#define REPS 50
#define THREADS 10

#include <thread>
#include <vector>

#if USE_STREAM
    #include <iostream>
#else
    #include <cstdio>
#endif

void task()
{
    for ( int i = 0; i < REPS; ++i )
#if USE_STREAM
        std::cout << std::hex << 15 << std::dec;
#else
        std::printf ( "%x", 15);
#endif

}

int main()
{
    auto threads = std::vector<std::thread> {};
    for ( int i = 0; i < THREADS; ++i )
        threads.emplace_back(task);

    for ( auto & t : threads )
        t.join();

#if USE_STREAM
        std::cout << "\n<iostream>\n";
#else
        std::printf ( "\n<cstdio>\n" );
#endif
}

이 예에 대한 반박은 대부분의 사람들이 여러 스레드에서 하나의 파일 기술자에 쓰지 않도록 훈련한다는 것입니다.그러다,그러다,그러다,그러다,.<iostream> ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★<< 모든 ★★★★★★★★★★★★★★★.>>, 반,에서는, . . ..<cstdio>자주 잠그지 않을 뿐만 아니라 잠그지 않을 수도 있습니다.

<iostream>더 많은 잠금을 소비하여 일관성 없는 결과를 얻을 수 있습니다.

것 에, 田른른른 in in in in in in in in in in in in in in in in in in in in in in in.
라는 사실도 있다std::endl같지 않다'\n'.

이것은 불행하게도 흔한 오해이다. std::endl 줄 '새 줄', '새 줄', '새 줄', '새 줄'이 아닙니다.
"새 을 인쇄한 다음 스트림을 플러싱합니다"라는 의미입니다.플러싱은 싸지 않아요!

의 차이를 완전히 무시하다printf ★★★★★★★★★★★★★★★★★」std::cout잠시 동안 C의 예시와 기능적으로 일치하기 위해 C++의 예시는 다음과 같습니다.

#include <iostream>

int main()
{
    std::cout << "Hello world\n";
    return 0;
}

플러시를 포함하면 다음과 같은 예가 있습니다.

C

#include <stdio.h>

int main()
{
    printf("Hello world\n");
    fflush(stdout);
    return 0;
}

C++

#include <iostream>

int main()
{
    std::cout << "Hello world\n";
    std::cout << std::flush;
    return 0;
}

코드를 비교할 때는 항상 유사한 비교와 코드 동작의 의미를 이해하는 데 주의해야 합니다.때때로 가장 간단한 예들조차도 몇몇 사람들이 깨닫는 것보다 더 복잡하다.

기존의 기술적인 답변은 맞지만, 이 질문은 결국 다음과 같은 오해에서 비롯되었다고 생각합니다.

C++에서는 당신이 먹는 것에 대해 돈을 낸다는 것은 유명하다.

이것은 C++ 커뮤니티의 마케팅 이야기일 뿐입니다.(공정하게 말하면, 모든 언어 커뮤니티에서 마케팅에 관한 이야기가 있습니다.)그것은 당신이 진지하게 의지할 수 있는 구체적인 어떤 것도 의미하지 않습니다.

"사용하는 기능에 대한 비용을 지불한다"는 것은 C++ 기능을 사용하는 경우 오버헤드만 발생한다는 것을 의미합니다.그러나 "a feature"의 정의는 무한히 세분화되어 있지 않습니다.많은 경우 여러 측면이 있는 기능을 활성화하게 됩니다.이러한 측면의 서브셋이 필요한 경우에도 구현에 기능이 부분적으로 도입되는 것은 실용적이지 않거나 불가능한 경우가 많습니다.

일반적으로 많은 언어(전부는 아니지만)는 효율화를 위해 노력하고 있으며 성공 정도는 다양합니다.C++는 체중계 어딘가에 있지만, 이 목표를 완벽하게 성공시킬 수 있는 특별한 디자인이나 마법 같은 것은 없습니다.

C++의 Input/Output 기능은 우아하게 쓰여져 사용하기 쉽도록 설계되어 있습니다.많은 점에서 C++의 객체 지향 기능에 대한 쇼케이스입니다.

그러나 그 대가로 약간의 퍼포먼스를 포기하는 것은 사실이지만, 운영체제가 낮은 수준에서 기능을 처리하는 데 걸리는 시간과 비교하면 무시할 수 있는 수준입니다.

C++ 규격의 일부이므로 언제든지 C 스타일 함수로 되돌릴 수 있습니다.또, 휴대성을 완전히 포기하고, operating system에의 다이렉트 콜을 사용할 수도 있습니다.

다른 답변에서 보셨듯이, 일반 라이브러리에서 링크하고 복잡한 컨스트럭터를 호출할 때 요금을 지불하셔야 합니다.여기엔 특별한 질문이 없고, 더 많은 불평이 있다.몇 가지 실제적인 측면을 짚어보겠습니다.

  1. Barne은 효율이 C++가 아닌 C에 머무르는 이유가 되지 않도록 하는 핵심 설계 원칙을 가지고 있었습니다.즉, 이러한 효율성을 얻기 위해서는 주의가 필요합니다.또한 C사양 내에서 항상 작동하지만 '기술적으로' 작동하지 않는 효율이 있는 경우도 있습니다.예를 들어 비트 필드의 레이아웃은 실제로 지정되지 않았습니다.

  2. 한 번 훑어보세요.세상에, 더부룩해!거기서 비행 시뮬레이터를 발견해도 놀라지 않을 거예요.stdlib의 printf()도 보통 약 50K를 실행합니다.이들은 게으른 프로그래머가 아닙니다.프린트프 크기의 절반은 대부분의 사람들이 사용하지 않는 간접적인 정밀 인수와 관련이 있습니다.거의 모든 제약이 있는 프로세서의 라이브러리는 printf 대신 자체 출력 코드를 만듭니다.

  3. 일반적으로 크기가 커짐에 따라 보다 억제되고 유연한 환경이 제공됩니다.예를 들어, 자판기는 커피와 같은 음료 한 잔을 동전 몇 개에 팔고 전체 거래는 1분도 걸리지 않는다.좋은 레스토랑에 들르는 것은 식탁 세팅, 앉기, 주문하기, 대기하기, 멋진 컵 받기, 계산서 받기, 원하는 형태로 계산하기, 팁 추가, 그리고 나가는 길에 좋은 하루 보내기를 바라는 것을 포함한다.이것은 다른 경험이며, 만약 당신이 친구와 함께 복잡한 식사를 하러 들른다면 더 편리합니다.

  4. 사람들은 여전히 ANSI C를 쓰지만, K&R C는 거의 쓰지 않습니다. 제 경험으로는 끌리는 것을 제한하기 위해 몇 가지 구성을 수정하여 항상 C++ 컴파일러로 컴파일합니다.다른 언어에는 다음과 같은 좋은 논거가 있습니다.Go는 다형성 오버헤드와 크레이지 프리프로세서를 제거합니다.더 스마트한 필드 패킹과 메모리 레이아웃에 대한 몇 가지 좋은 주장이 있습니다.IMHO 어떤 언어 디자인도 Python의 Zen과 마찬가지로 목표의 리스트에서 시작해야 한다고 생각합니다.

재미있는 토론이었어요.마법처럼 작고 심플하며 우아하고 완전하고 유연한 라이브러리를 가질 수 없는 이유를 물으셨습니다.

응답이 없는데요.답이 없을 것이다.그게 답이에요.

언급URL : https://stackoverflow.com/questions/52442415/in-c-am-i-paying-for-what-i-am-not-eating

반응형