Jump to content

  • Log In with Google      Sign In   
  • Create Account


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


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • This topic is locked This topic is locked
70 replies to this topic

#21 mrbastard   Members   -  Reputation: 1573

Posted 18 July 2011 - 06:21 AM

Would love to see a fight between Linus Torvalds and Alex Stepanov. I think they'd each lose an eye before working out that they agree OO is the root of all evil.


Sponsor:

#22 phantom   Moderators   -  Reputation: 7155

Posted 18 July 2011 - 06:27 AM

before working out that they agree OO is the root of all evil.


Then two people would be wrong, yay!

There is nothing wrong with OO done correctly, the 'problem' is the lack of design skills, critial thinking and correctly applying paradigms to solve a problem.

The problem is most people don't have those skills but then again chances are they would write bad code in any paradigm if left to their own devices...

#23 mrbastard   Members   -  Reputation: 1573

Posted 18 July 2011 - 07:07 AM

There is nothing wrong with OO done correctly, the 'problem' is the lack of design skills, critial thinking and correctly applying paradigms to solve a problem.

The problem is most people don't have those skills but then again chances are they would write bad code in any paradigm if left to their own devices...


Oh, I agree. I've just always found it funny that many c programmer's arguments against c++ revolve around inheritance, when the guy who designed the STL has pretty much the same opinion! Posted Image I'd very much enjoy watching Stepanov and Torvalds direct their arguments at one another in some kind of forum trollocalypse.

In the linked rant (in between attempts at trolling) Torvalds says similar to what you say about lack of skills. Stepanov, for all his hatred of OO, presumeably likes that in c++ you can have a function object whose operator() can be inlined, unlike a c function ptr. So he doesn't mind objects, just OO...... Posted Image

Personally, I think the problem is that 'OO done correctly' means different things in different languages and different problem spaces, which has lead to people having the skills and wanting to apply them, but applying them wrongly for c++ in performance-critical situations. There's a wealth of OO design wisdom out there, and while most of it can be applied to c++ design, not all of it should have been. For example, classical OO literature revolves around using inheritance for polymorphism, which is not always the best way to go in c++ where we have lovely compile-time polymorphism.

(insert obligatory comment about OO being possible in c and the OO argument therefore being irrelevant to this thread anyway - if I didn't someone else would!)


#24 braindigitalis   Members   -  Reputation: 150

Posted 18 July 2011 - 09:29 AM

This opinion that C is 'better than' C++ for various problem domains is rampant in the open source community.
Before making my way back to game development i spent many years writing an irc daemon (ircd). I was often beset with idiots telling me that because i had chosen to write such a program in C++, it simply would not scale, would take all available RAM in the server, that inheritence would make it slow, and other quite frankly stupid arguments.

Needless to say most of these people did not believe that you should choose the right tool for the job. In this particular case, the right tool for the right job, based on my skillsets and the requirements of the application, were C++.

If i was to approach the same problem again today maybe i would not choose C++, but i definitely still would not choose C.

#25 Calmatory   Members   -  Reputation: 116

Posted 18 July 2011 - 09:38 AM

The answer is extremely simple. Three points.
1) Portability. C is the most portable language out there.
2) Simplicity. Most low level code does not require C++ features.
3) Efficiency. C code is often both faster and smaller than C++ code. There's a reason why there are no interesting 1k/4k demos written in C++, because it is shit for size optimized code. :)
The interesting question would be "Why should anyone use C++ in low level code?". :)
Note that with C++ code I actually mean proper OO+exceptions+templates kind of code. Sure, you can write pure C and compile it with C++ compiler and claim that "Oh but it IS valid C++!" but it defeats the whole purpose of the discussion.

This opinion that C is 'better than' C++ for various problem domains is rampant in the open source community.
Before making my way back to game development i spent many years writing an irc daemon (ircd). I was often beset with idiots telling me that because i had chosen to write such a program in C++, it simply would not scale, would take all available RAM in the server, that inheritence would make it slow, and other quite frankly stupid arguments.

Needless to say most of these people did not believe that you should choose the right tool for the job. In this particular case, the right tool for the right job, based on my skillsets and the requirements of the application, were C++.

If i was to approach the same problem again today maybe i would not choose C++, but i definitely still would not choose C.


This is because you don't care about portability. You only wanted your ircd run on your own system.

I myself write code which has to run from routers to super computers, so anything except C is a definite no-go for me, because the code HAS to compile on those machines which run operating systems and CPU and hardware architectures unknown to me. Everything I care about is conforming to C89, POSIX and SUS(Single Unix Specification) standards.




#26 Aardvajk   Crossbones+   -  Reputation: 5968

Posted 18 July 2011 - 09:55 AM

C code is often both faster and smaller than C++ code.


Again, examples please. These spurious claims are making the thread feel like groundhog day.

Note that with C++ code I actually mean proper OO...


You probably don't mean "proper" OO, which is entirely possible in almost any language.

...+exceptions+templates kind of code.


Aargh. Templates do not cause overhead. Having multiple versions of a function for different types is not overhead, if those multiple versions are required. Writing and maintaining several versions of a function does cause overhead - programmer overhead, e.g. time, money and sanity.

Sure, you can write pure C and compile it with C++ compiler and claim that "Oh but it IS valid C++!" but it defeats the whole purpose of the discussion.


Yeah, you can also write C++ code that uses none of the supposedly expensive features above, no additional overhead compared to a C program and all the added benefits of type safety.

There are only two sane reasons to prefer C over C++ in my view - a) there does not exist a well-proven C++ compiler for a given platform or b) the programmers available for the job at an acceptable cost are experienced in C, not C++.

Both are valid real-world reasons. Neither have anything whatsoever to do with the nature of C++, except possibly its younger age than C.

And, as a footnote, all of Linus T's arguments seem to be about C++ programmers, not about C++. But then I haven't written an operating system filled with comments like "// this is a hack, we have no idea how it works" so what do I know?

#27 braindigitalis   Members   -  Reputation: 150

Posted 18 July 2011 - 10:29 AM

This is because you don't care about portability. You only wanted your ircd run on your own system.

I myself write code which has to run from routers to super computers, so anything except C is a definite no-go for me, because the code HAS to compile on those machines which run operating systems and CPU and hardware architectures unknown to me. Everything I care about is conforming to C89, POSIX and SUS(Single Unix Specification) standards.




I am sorry but this is an incorrect and hastily entered response. The software in question is extremely popular, in use by many hundreds of networks, and definitely not just designed 'for my own computer'. I myself run a 600 user network on it and there are many other networks of 3000 users and up that use the same software. Maybe you should take a look at the project website (http://www.inspircd.org) and reconsider your kneejerk response to my post.

#28 Washu   Senior Moderators   -  Reputation: 5041

Posted 18 July 2011 - 11:44 AM

Moved to the lounge, a more appropriate venue for "C vs C++" or any of the other common examples of X vs Y you can think of.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX


#29 Calmatory   Members   -  Reputation: 116

Posted 18 July 2011 - 12:17 PM

Argh. I wrote a long-ish post for almost an hour. Topic moved and the forum itself being rather unfriendly(messing the text layout and indentations), dundun. Since I'm in a hurry I'll just leave these here for now:

Here's a simple example:


C:

#include <stdio.h>

int main(int argc, char *argv[]) {
    int i=0;
    int j=0;
    char name[32];
    for(i=0;i<8192;i++) {
        printf("Argument count: %d\n", argc);
        for(j=0;j<argc;j++) {
            printf("Name: %s\n", argv[j]);
        }
    }
    scanf("%32s", (char*)&name);
    printf("Hello %s!\n", name);
    return 0;
}


C++:

#include <iostream>
#include <string>

int main(int argc, char *argv[]) {
    std::string name;
    for(int i=0;i<8192;i++) {
        std::cout << "Argument count: " << argc << std::endl;
        for(int j=0;j<argc;j++) {
            std::cout << "Name: " << argv[j] << std::endl;
        }
    }
    std::cin >> name;
    std::cout << "Hello " << name << "!" << std::endl;
    return 0;
}










results:

[calmis@purpleorange cvscpp]$ g++ main.cpp -o main2 -O0 -Wall -Wextra
[calmis@purpleorange cvscpp]$ gcc main1.c -o main1 -O0 -Wall -Wextra
[calmis@purpleorange cvscpp]$ time echo "Dun-dun Daa" | ./main2 a ab abc abcd abcde abcdef abcdefg > mainCPP.txt

real 0m0.314s
user 0m0.063s
sys 0m0.203s
[calmis@purpleorange cvscpp]$ time echo "Dun-dun Daa" | ./main1 a ab abc abcd abcde abcdef abcdefg > mainC.txt

real 0m0.046s
user 0m0.023s
sys 0m0.000s
[calmis@purpleorange cvscpp]$ wc -c main2
8048 main2
[calmis@purpleorange cvscpp]$ wc -c main1

5213 main1

Size optimizations turned on:


[calmis@purpleorange cvscpp]$ g++ main.cpp -o main2 -Os -s -Wall -Wextra
[calmis@purpleorange cvscpp]$ gcc main1.c -o main1 -Os -s -Wall -Wextra
[calmis@purpleorange cvscpp]$ time echo "Dun-dun Daa" | ./main2 a ab abc abcd abcde abcdef abcdefg > mainCPP.txt

real 0m0.326s
user 0m0.043s
sys 0m0.227s
[calmis@purpleorange cvscpp]$ time echo "Dun-dun Daa" | ./main1 a ab abc abcd abcde abcdef abcdefg > mainC.txt

real 0m0.035s
user 0m0.023s
sys 0m0.000s
[calmis@purpleorange cvscpp]$ wc -c main2
5132 main2
[calmis@purpleorange cvscpp]$ wc -c main1
3508 main1




9.3x faster, some 1.4x smaller.

C functions with void* arguments and a variable to denote the types, and then using switch() to invoke right code(assuming that e.g. 8, 16, 32 and 64 bit ints can share the same code) is more size-efficient than C++ with templates.

I rest my case for now.



#30 Rattrap   Members   -  Reputation: 1623

Posted 18 July 2011 - 12:31 PM

Change those std::endl to '\n' and you see a big difference. You are flushing the buffer after every call using std::endl;
Also, to make the code a little closer to the C version, reserve some memory for the string.




#include <iostream>
#include <string>

int main(int argc, char *argv[]) {
    std::string name;
    name.reserve(32);
    for(int i=0;i<8192;i++) {
        std::cout << "Argument count: " << argc << '\n';
        for(int j=0;j<argc;j++) {
            std::cout << "Name: " << argv[j] << '\n';
        }
    }
    std::cin >> name;
    std::cout << "Hello " << name << "!" << std::endl;
    return 0;
}


C++
real 0m0.042s
user 0m0.030s
sys 0m0.010s

C
real 0m0.029s
user 0m0.020s
sys 0m0.007s

[edit]
Added link about std::endl.

#31 Antheus   Members   -  Reputation: 2397

Posted 18 July 2011 - 12:43 PM

9.3x faster, some 1.4x smaller.


Wrong conclusion.

The problem is IO bound, so heuristics on buffer sizes will determine the running time.

Change those std::endl to '\n' and you see a big difference.


Also disable sync with stdio, I forgot exactly how. I think it's disable_sync_with_stdio() or similar.

#32 braindigitalis   Members   -  Reputation: 150

Posted 18 July 2011 - 01:09 PM

I don't think you are able to measure the performance of a language with an artificial benchmark such as this. An artificial benchmark can be designed to prove that any X is 'better than' Y for any specific benchmark.

Every language has specific traits that outweigh some other language, and this is what matters. In the end, holy wars with 'X vs Y' do nothing but serve to cause arguments and usually are based in nothing but heresay and personal opinion without solid proof.

Use the right tool to solve the problem, without trying to use an excavator to swat a fly, and you will prosper. :-)

(EDIT: 1.6 million google results are here saying why it is not a good idea to trust such benchmarks).

Edited by braindigitalis, 18 July 2011 - 01:11 PM.


#33 Calmatory   Members   -  Reputation: 116

Posted 18 July 2011 - 01:09 PM

Thanks for replies. I tried with \n, reserved some space for the string and disabled the sync with following results:

[calmis@purpleorange cvscpp]$ time echo "Dun-dun Daa" | ./main1 a ab abc abcd abcde abcdef abcdefg > mainC.txt

real 0m0.035s
user 0m0.017s
sys 0m0.007s
[calmis@purpleorange cvscpp]$ time echo "Dun-dun Daa" | ./main2 a ab abc abcd abcde abcdef abcdefg > mainCPP.txt

real 0m0.055s
user 0m0.033s
sys 0m0.003s


Obviously the speed bottleneck in this case is/was due to a incompetent programmer(me). However, there's still the size problem to solve. With GCC 4.6 the sizes are:

[calmis@purpleorange cvscpp]$ wc -c main1
3508 main1
[calmis@purpleorange cvscpp]$ wc -c main2
5944 main2


...when compiled with -Os and -s flags. This is my main point when working with embedded systems which do not necessarily have the resources to spare for increased code size.

But as stated numerous times before, the main reason for preferring C over C++(at least to date) has been with portability and habit.




I don't think you are able to measure the performance of a language with an artificial benchmark such as this. An artificial benchmark can be designed to prove that any X is 'better than' Y for any specific benchmark.

Every language has specific traits that outweigh some other language, and this is what matters. In the end, holy wars with 'X vs Y' do nothing but serve to cause arguments and usually are based in nothing but heresay and personal opinion without solid proof.

Use the right tool to solve the problem, without trying to use an excavator to swat a fly, and you will prosper. :-)



This is completely true. It is not possible to draw conclusions about the whole language based on single benchmarks really. However, I was asked for an example which demonstrates that C indeed is more resource efficient than C++, and I brought in one, very simple example of this. And it gets even worse when one starts using more than just the standard C++ library, e.g. classes, multiple inheritance and exceptions. This is based on my experience when working with 1k/4k demoscene prods, in which C++ is a definite no-go because of the increased resulting binary size. If size doesn't matter(what!?), then C++ is much more attractive for me at least. But as shown above, I am not a C++ dev at all really. :)



#34 ApochPiQ   Moderators   -  Reputation: 15164

Posted 18 July 2011 - 01:19 PM

Did you remember to strip symbols and debug information from your binary after you compiled it?

#35 braindigitalis   Members   -  Reputation: 150

Posted 18 July 2011 - 01:20 PM

This is based on my experience when working with 1k/4k demoscene prods, in which C++ is a definite no-go because of the increased resulting binary size.


Ahh, the nostalgia, i remember when these were written in assembly language, not C :cool:

#36 Calmatory   Members   -  Reputation: 116

Posted 18 July 2011 - 01:39 PM

Did you remember to strip symbols and debug information from your binary after you compiled it?


With external tools? Not really, but after doing that the results are as follows:


[calmis@purpleorange cvscpp]$ wc -c main1
3508 main1
[calmis@purpleorange cvscpp]$ wc -c main2
5944 main2
[calmis@purpleorange cvscpp]$ strip -R .comment -R .gnu.version main1
[calmis@purpleorange cvscpp]$ strip -R .comment -R .gnu.version main2
[calmis@purpleorange cvscpp]$ sstrip main1
[calmis@purpleorange cvscpp]$ sstrip main2
[calmis@purpleorange cvscpp]$ wc -c main1
2048 main1
[calmis@purpleorange cvscpp]$ sstrip main2
[calmis@purpleorange cvscpp]$ wc -c main2
4424 main2



The reason why I excluded this in the first place was that when working with embedded systems often there are no such tools to use, so they'd just skew the results.


This is based on my experience when working with 1k/4k demoscene prods, in which C++ is a definite no-go because of the increased resulting binary size.


Ahh, the nostalgia, i remember when these were written in assembly language, not C :cool:



These days optimizing compiler can generate pretty much quite damn optimal assembly from C, and OS-specific tricks and external strippers/packers/crunchers have advanced very much during the past few years or so to further reduce the gap between C and asm. Writing a barebone sketch with C and optimizing the rest by hand in asm is the way to go.

#37 phantom   Moderators   -  Reputation: 7155

Posted 18 July 2011 - 02:07 PM

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)

#38 Ravyne   Crossbones+   -  Reputation: 7128

Posted 18 July 2011 - 02:27 PM

A big reason is that "embedded" systems span an incredible range of devices and processors -- typically, anyone with an odd-ball processor or who sells their own microcontrollers is also in the position of having to develop and maintain their own tool-hains, run-times, etc -- C is simply the easiest path, and probably about an order of magnitude less difficult to implement and support.

There's also a certain amount of historical bias / tribalism among codgy old embedded developers, who probably gave up assembly with a fair bit of reluctance. In the wide, this means that much of the ecosystem is built around C. C++ is making inroads on more capable platforms (eg, MIPS/PowerPC platforms), but C is still king elsewhere, and probably will be for quite some time.

It's also true that, when a custom solution is called for, its far more straight-forward to build something on top of C, than to try to undo/work around what C++ has by default and replace it with your own -- I'm not talking about memory allocation here, I mean things like providing some sort of (psuedo-)object system built to be performant on the device.

You're right that C++ does have quite a few other features that are useful to embedded dev though -- for example, you could concievably use placement new to initialize memory-mapped devices using the class constructor, and template meta-programming can be used to generate highly-tuned code parametrically.

#39 typedef struct   Members   -  Reputation: 230

Posted 18 July 2011 - 03:24 PM

Mostly because C++ doesn't help solve the problems that "low level code" is facing. It's considerably easier to guess what's going on under the hood with a C program compared to a C++ program. Virtual functions make it difficult to determine what code will run next. Templates make it difficult to determine what code even exists. C++ tries to be type-safe, where C doesn't. Sometimes you pay a performance cost for this type safety, sometimes you don't, but afaik you never get a performance win out if it (like OCaml purports to do).

So, if you're writing code, and all of the domain momentum is geared toward C (existing code, libraries, developer skillsets), it's very difficult to justify moving to C++. It's a similar situation with C++ vs a higher level language for games.
Anthony Umfer

#40 Hodgman   Moderators   -  Reputation: 29700

Posted 18 July 2011 - 06:47 PM

I rest my case for now.

As mentioned by phantom, that's a completely false benchmark, as both programs aren't doing the same thing at all, you've made the C++ one do a ton more work than the C one.


You may as well have written:
//C benchmark
for( int i=0; i<1; ++i ){printf("");}
//C++ benchmark
for( int i=0; i<10000; ++i ){printf("");}

Mostly because C++ doesn't help solve the problems that "low level code" is facing. It's considerably easier to guess what's going on under the hood with a C program compared to a C++ program. Virtual functions make it difficult to determine what code will run next. Templates make it difficult to determine what code even exists.

That's a completely false argument -- the C equivalent of virtual functions are function pointers. The C equivalent of templates are #include-templates.
If you used those same methodologies in both languages, you'd have the same problems in both languages.

Not all C++ programs are written using the wrong features at the wrong time. Just because you're using C++ everywhere, it doesn't mean you should go and use virtual for something where you wouldn't have used a function-pointer in C. If you do, then you're just a shit C++ programmer, and the argument becomes "good programmers are better than shit programmers, derp!".




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS