why is C++ not commonly used in low level code?

Started by
67 comments, last by Washu 12 years, 9 months ago
With regards to Linus Torvalds and Linux:
  • C is used in Linux because of its versatility. It can do everything C++ can do, but also gives you fined-tuned control over every aspect of program at the cost of expertise. This "theme" is the very core of Linux--to have a OS that is extremely versatile, but often times harder to run without the expertise (which is why the two work hand-in-hand). Here is a quick example of this:
    • In C++ it has built-in OO functionality via classes. This makes things such as polymorphism much easier. BUT, by using classes you loose control of how object pointers are handled in the member functions, you loose control of how constructors/destructors are called and when, how member-function pointers are stored within the structure, etc etc.
    • In C you can still do OO programming just like C++ classes by using structures and callbacks via function pointers. But, you get the ultimate control of how everything happens. YOU decide when constructors/destructors are called, YOU decide how object pointers are passed to member-functions, and YOU decide how member function pointers are stored in the structure and how they are alligned.
    • By having this fine-control in C it allows you to write extremely fast and efficient code, while still doing everything C++ does. Here are a couple of examples:
      • I could choose a special alignment of the function pointers that could produce huge performance boosts on certain systems.
      • I could choose to pass the object pointer to the member function via the stack instead of a register, thus saving the register for a different parameter--which when used right, could provide huge performance boosts.
      • Etc etc.
  • C is typically more compatible with other programming languages(particularly that of scripted languages)--which makes creating wrappers much easier (scripted languages is a huge part of Linux).
  • Although C++ isn't inherently a bad/inefficient language, the concepts it introduces often times leads to poor code. Because Linux is open-source and has thousands of contributors, having perfect, well-written code is a must. Here is a quick example:
    • In C++ I am writing a bubble-sorting algorithm to sort a list of strings alphabetically. In C++ the quick'n'easy solution would be to store the strings as a std::string, and store the group of strings as a std::vector. Once sorting, each time I swap two strings a total of 10 things happen: A) a extra std::string constructor is called, and B) 3 memory-free operations, and C) 3 memory-alloc operations, and 3 memory-copy operations. If each string is 10,000 characters in size, and there are 40,000 strings your looking at a huge overhead implementing it this way.
    • In C, one would simply allocate an array of 40,000 char ** pointers, then alloc each pointer with a pointer to 10,000 characters each. An extra 10,000 character buffer would be needed for the swapping stage. Now, once sorting, 3 things would happen to swap two strings: a total of 3 memory-copy operations. This is much simpler, and scores faster in nature than the obvious C++ implementation. In addition, because you have direct access to the char ** and char * pointers you can modify their alignment, as well as using the registers to store the generic pointers, in order to achieve additional performance boosts.
    • Additionally, by using std::string and std::vector you import a gargantuan hunk of code to your project. If executable size, compile-time, or load-time are a concern than C is definitely the winner.
  • I am not bashing on C++, I know a lot of people like it. For me, and obviously Linus + Linux, C is the way to go :). Its really just a matter of opinion.
    Advertisement

    2 points;

    1) std::cin and std::cout are doing more than the scanf and printf under the hood, which are both valid C++ functions btw and thus any coder worth their salt would use them if the situation required it*
    2) As soon as the input string exceeds 32 characters your C code runs the risk of blowing up nicely; the C++ version is safe in that regard.

    (* it becomes a speed vs safety trade off... if you want speed then you'd take the functions with the lowest overhead, if you want safey then you have to ditch some of that speed)


    You are right, and I did this on purpose. As I mentioned before, with C++ I mean as "pure" C++ as it gets. It's no use to exploit as much C feature-set with C++ code and go all "But this IS valid C++ too!". There's no way to define when to stick to C library or when to use the C++ equivalents. Though, my main point for C is still it's portability(well supported on numerous platforms) and simplicity(Not so hard to write/port a custom compiler for custom hardware).





    Since people have been critical towards the example I gave, I challenge others to write example code too for us all to learn more from.


    • C is used in Linux because of its versatility. It can do everything C++ can do, but also gives you fined-tuned control over every aspect of program at the cost of expertise. This "theme" is the very core of Linux--to have a OS that is extremely versatile, but often times harder to run without the expertise (which is why the two work hand-in-hand). Here is a quick example of this:
      • In C++ it has built-in OO functionality via classes. This makes things such as polymorphism much easier. BUT, by using classes you loose control of how object pointers are handled in the member functions, you loose control of how constructors/destructors are called and when, how member-function pointers are stored within the structure, etc etc.
      • In C you can still do OO programming just like C++ classes by using structures and callbacks via function pointers. But, you get the ultimate control of how everything happens. YOU decide when constructors/destructors are called, YOU decide how object pointers are passed to member-functions, and YOU decide how member function pointers are stored in the structure and how they are alligned.
      • By having this fine-control in C it allows you to write extremely fast and efficient code, while still doing everything C++ does. Here are a couple of examples:
        • I could choose a special alignment of the function pointers that could produce huge performance boosts on certain systems.
        • I could choose to pass the object pointer to the member function via the stack instead of a register, thus saving the register for a different parameter--which when used right, could provide huge performance boosts.
        • Etc etc.
    I know that you know that you can do all of that in C++ as well as in C....
    So... all this really means is that a shit C++ programmer is worse than a good C programmer?
    Shit is worse than good?
    Ok.

    [font="arial, verdana, tahoma, sans-serif"]
    You are right, and I did this [wrote an invalid benchmark] on purpose. As I mentioned before, with C++ I mean as "pure" C++ as it gets.
    You're just demonstrating that you don't know C++ very well then, as instead of using a heavyweight formatted and localized output stream, you could've used a lightweight one that was a better analog of [/font][font="Courier New"]printf[/font]... Or if the task really needed [font="Courier New"]printf[/font], a good C++ programmer might just use [font="Courier New"]printf[/font].
    It's no use to exploit as much C feature-set with C++ code and go all "But this IS valid C++ too!".[/quote]Why?
    We use C++ for a ton of low-level stuff at work, most of it without the use of [font="Courier New"]virtual[/font], etc...
    It's very "C-like" in style, but we've got a few extra tools to play with as well.
    e.g. you said before that in C++ you give up control over when constructors/destructors are called, but in some very low-level code, we use placement-new ([font="Courier New"]new (preAllocatedBuffer) T()[/font]) and explicit destructor calls ([font="Courier New"]p->~T()[/font]) to do exactly that. A lot of our low-level code does take the reigns and make explicit decisions about all the things you say that you're giving up in C++.
    Again, your idea of what "typical C++" is, is not at all what good C++ programmers write, and yes, it is C++, not C.

    You really are just saying that shit C++ is worse than good C code... or that because you've got extra tools in your tool-box, you're somehow forced to use them for every problem? What's wrong with having a few extra tools that you only pull out occasionally?
    C is used in Linux because of its versatility. It can do everything C++ can do, but also gives you fined-tuned control over every aspect of program at the cost of expertise.


    Brainfuck can do everything C can do, but also gives you fine-tuned control over every atomic instruction of your program at the cost of expertise. So why isn't Linux written in Brainfuck?

    Because your argument is fallacious. C does not do everything C++ does, in the sense that C does not provide black-box abstractions that C++ provides. This means that C is fundamentally a less productive language when comparing the efficiency of experts in either language.

    In C++ it has built-in OO functionality via classes. This makes things such as polymorphism much easier. BUT, by using classes you loose control of how object pointers are handled in the member functions, you loose control of how constructors/destructors are called and when, how member-function pointers are stored within the structure, etc etc.[/quote]

    Bullshit.

    Object pointers are always passed using thiscall, i.e. in the first (hidden) parameter to the function. This is not magic and does not remove anything. In fact, you can write a shim that translates from arbitrary C-style pointer passing to thiscall in three lines of code:

    int InvokeFoo(int argument1, int argument2, Foo* ptr)
    {
    ptr->FooImpl(argument1, argument2);
    }


    Construction and destruction are performed in very, very well defined ways and in well defined orders. I suspect you don't know C++ very well if you aren't aware of how to reason about construction and destruction order in a program. For stack-allocated objects it's bloody trivial; for free-store-allocated objects, it's only slightly more complex due to the presence of placement new and explicit destructor invocation. But those things give you perfect control over construction and destruction patterns, not remove control.

    Your last "argument" is nonsensical. My best guess is that this is some oblique reference to the vtable, which is hardly something you need to tamper with... well, ever, really, in a proper C++ program. And guess what? If you're psycho and really want to write your own vtable, C++ has member function pointer syntax which lets you do so, while retaining thiscall semantics.

    So there is absolutely no loss of control here - you just personally don't know how to obtain that control, apparently.

    In C you can still do OO programming just like C++ classes by using structures and callbacks via function pointers. But, you get the ultimate control of how everything happens. YOU decide when constructors/destructors are called, YOU decide how object pointers are passed to member-functions, and YOU decide how member function pointers are stored in the structure and how they are alligned.[/quote]

    I control all of that in C++ too. And, what's better, I don't have to think about it 99% of the time, because the language makes certain default guarantees that accommodate the vast majority of use cases with no issue.

    And, guess what, I can still control all of that by hand if I really want to.

    I could choose a special alignment of the function pointers that could produce huge performance boosts on certain systems.[/quote]

    AFAIK any decent C++ compiler will native-align the vtable entries; in fact, they'd almost have to bend over backwards not to, because vtable entries are by definition machine pointer size to begin with. So I don't think you really know what you're comparing with here.

    I could choose to pass the object pointer to the member function via the stack instead of a register, thus saving the register for a different parameter--which when used right, could provide huge performance boosts.[/quote]

    You can implement your own calling convention on top of thiscall trivially in C++, if you know what you're doing. (Compiler specific, of course.)

    In C++ I am writing a bubble-sorting algorithm to sort a list of strings alphabetically. In C++ the quick'n'easy solution would be to store the strings as a std::string, and store the group of strings as a std::vector. Once sorting, each time I swap two strings a total of 10 things happen: A) a extra std::string constructor is called, and B) 3 memory-free operations, and C) 3 memory-alloc operations, and 3 memory-copy operations. If each string is 10,000 characters in size, and there are 40,000 strings your looking at a huge overhead implementing it this way.[/quote]

    Or you could use std::string::swap like any first-year C++ student would know to do, and your C++ program boils down to the C program with extra type safety and memory management safety.


    The vast majority of people who argue against C++ are not arguing against the language itself, but rather against people who don't know how to use the language. Granted, crappy C++ "programmers" are a dime a dozen, so caveat emptor - but there's no really good argument for C over C++ that actually has to do with the languages themselves. It's all down to comparing tools, relying on history, selecting for certain types of programmers, or bigotry.

    Wielder of the Sacred Wands
    [Work - ArenaNet] [Epoch Language] [Scribblings]


    You really are just saying that shit C++ is worse than good C code... or that because you've got extra tools in your tool-box, you're somehow forced to use them for every problem? What's wrong with having a few extra tools that you only pull out occasionally?

    So what would your conclusion be for both C and C++? A right tool for the right task? What tasks are right for C but not C++? What tasks are right for C++ and not C?

    I'm still waiting for better code examples. Indeed, I am a shit C++ programmer, which doesn't take away the fact that C++ is bloaty when compared to C(yes, I provoke on purpose. Prove me wrong :P). And this is one of the reasons why C is preferred over C++ in many low level tasks.



    Indeed, I am a shit C++ programmer

    And that is exactly the problem. How can you make statements about a language you admittedly have low expertise in ? The "benchmark" example you provided earlier is the perfect example of that. You were comparing two pieces of code that had nothing at all in common except for outputing text. That text editor written in C is faster than that protein-folding simulator written in C++. Obviously this must mean that C is better...

    In fact this is something one can observe in almost all C vs C++ discussions. The most rabid C defenders (explicitly including Linus Torvalds) have actually very little knowledge of C++, sometimes leading to almost absurd arguments.


    which doesn't take away the fact that C++ is bloaty when compared to C(yes, I provoke on purpose. Prove me wrong :P)

    Prove yourself wrong by learning C++ before making factually incorrect statements about it. Counter arguments to your points are trivial common knowledge to every semi-competent C++ programmer.
    I did not base my judgment solely on the code I provided and it's size, but also on my past experience with it for writing small code(binary size sub 1024/4096 bytes) and the common practices in demoscene. Instead of ranting, teach me. Show me. I'm asking for fourth time for someone to show how things are done correctly, and I'd appreciate it if it actually showed that C++ would be more ideal for low-level development than C. Especially for embedded systems in which resources are scarce.




    I'm waiting for code.

    memes-you-code-in-c-son-i-am-disappoint.jpg

    *Note: I code in C++. I just thought I'd share the laughs.
    I'm that imaginary number in the parabola of life.

    So what would your conclusion be for both C and C++? A right tool for the right task? What tasks are right for C but not C++? What tasks are right for C++ and not C?
    IMHO, C is the right choice if:
    * you've got a team who are good C programmers but bad at C++, and you don't trust them to not write bad C++ code (pitfalls of OOP is a good example of the performance disaster that bad C++ can lead to).
    * you're on a platform with a good C compiler but a bad C++ compiler.
    * you really want to use some C99 feature that isn't supported in your C++ compiler for some reason.

    Instead of ranting, teach me. Show me. I'm asking for fourth time for someone to show how things are done correctly, and I'd appreciate it if it actually showed that C++ would be more ideal for low-level development than C. Especially for embedded systems in which resources are scarce. I'm waiting for code.
    I'm not going to fix your hello-world [font="Courier New"]printf[/font] vs [font="Courier New"]cout[/font] loop, because it's just a hello-world problem and has no relation to any real problems. Does anyone even use [font="Courier New"]cout[/font], in anything but "hello world"? tongue.gif

    I'm too busy writing high-performance C++ for embedded devices to tutor you right now, but the folks at Dice have some presentations on how to not write bad C++ that you should absolutely read: http://publications....ory=Engineering. The 'Scope Stack Allocation' presentation is a particularly good gem.
    You'll be happy to see that the result is very "C style" wink.gif
    Indeed, the presentations are real gems! Thanks for them, very interesting. I guess it's needless to say at this point that to make the most out of C++, it has to be very C-like, perhaps even relying on the C library rather than the C++ one?

    This topic is closed to new replies.

    Advertisement