In C++, am I paying for what I am not eating?

后端 未结 13 1932
既然无缘
既然无缘 2020-12-12 12:39

Let\'s consider the following hello world examples in C and C++:

main.c

#include 

int main()
{
    printf(\"Hello world\\n\");
    r         


        
相关标签:
13条回答
  • 2020-12-12 13:06

    I see some valid answers here, but I'm going to get a little bit more into the detail.

    Jump to the summary below for the answer to your main question if you don't want to go through this entire wall of text.


    Abstraction

    So, in this case, what am I paying for?

    You are paying for abstraction. Being able to write simpler and more human friendly code comes at a cost. In C++, which is an object-oriented language, almost everything is an object. When you use any object, three main things will always happen under the hood:

    1. Object creation, basically memory allocation for the object itself and its data.
    2. Object initialization (usually via some init() method). Usually memory allocation happens under the hood as the first thing in this step.
    3. Object destruction (not always).

    You don't see it in the code, but every single time you use an object all of the three above things need to happen somehow. If you were to do everything manually the code would obviously be way longer.

    Now, abstraction can be made efficiently without adding overhead: method inlining and other techniques can be used by both compilers and programmers to remove overheads of abstraction, but this is not your case.

    What's really happening in C++?

    Here it is, broken down:

    1. The std::ios_base class is initialized, which is the base class for everything I/O related.
    2. The std::cout object is initialized.
    3. Your string is loaded and passed to std::__ostream_insert, which (as you already figured out by the name) is a method of std::cout (basically the << operator) which adds a string to the stream.
    4. cout::endl is also passed to std::__ostream_insert.
    5. __std_dso_handle is passed to __cxa_atexit, which is a global function that is responsible for "cleaning" before exiting the program. __std_dso_handle itself is called by this function to deallocate and destroy remaining global objects.

    So using C == not paying for anything?

    In the C code, very few steps are happening:

    1. Your string is loaded and passed to puts via the edi register.
    2. puts gets called.

    No objects anywhere, hence no need to initialize/destroy anything.

    This however doesn't mean that you're not "paying" for anything in C. You are still paying for abstraction, and also initialization of the C standard library and dynamic resolution the printf function (or, actually puts, which is optimized by the compiler since you don't need any format string) still happen under the hood.

    If you were to write this program in pure assembly it would look something like this:

    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
    

    Which basically only results in invoking the write syscall followed by the exit syscall. Now this would be the bare minimum to accomplish the same thing.


    To summarize

    C is way more bare-bone, and only does the bare minimum that is needed, leaving full control to the user, which is able to fully optimize and customize basically anything they want. You tell the processor to load a string in a register and then call a library function to use that string. C++ on the other hand is way more complex and abstract. This has enormous advantage when writing complicated code, and allows for easier to write and more human friendly code, but it obviously comes at a cost. There's always going to be a drawback in performance in C++ if compared to C in cases like this, since C++ offers more than what's needed to accomplish such basic tasks, and thus it adds more overhead.

    Answering your main question:

    Am I paying for what I am not eating?

    In this specific case, yes. You are not taking advantage of anything that C++ has to offer more than C, but that's just because there's nothing in that simple piece of code that C++ could help you with: it is so simple that you really do not need C++ at all.


    Oh, and just one more thing!

    The advantages of C++ may not look obvious at first glance, since you wrote a very simple and small program, but look at a little bit more complex example and see the difference (both programs do the exact same thing):

    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;
    }
    

    Hopefully you can clearly see what I mean here. Also notice how in C you have to manage memory at a lower level using malloc and free how you need to be more careful about indexing and sizes, and how you need to be very specific when taking input and printing.

    0 讨论(0)
提交回复
热议问题