233

In listening to the Stack Overflow podcast, the jab keeps coming up that "real programmers" write in C, and that C is so much faster because it's "close to the machine." Leaving the former assertion for another post, what is special about C that allows it to be faster than other languages?

Or put another way: what's to stop other languages from being able to compile down to binary that runs every bit as fast as C?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mike C.
  • 4,917
  • 8
  • 34
  • 38
  • 7
    Can you list which particular show talked about this? I would love to hear it. – Giovanni Galbo Jan 07 '09 at 03:22
  • 2
    Really surprised at how badly this question is answered (most answers ignore the fundamental differences between compiled and interpreted languages etc, I know about JIT yada yada yada), and how many people are taking a position 'defending' their fave language (FORTRAN boy needs to take a pill). – Tim Ring Jan 09 '09 at 14:20
  • 1
    Don't forget assembly language. Nothing is faster or more compact than assembly-assembled exes. Assembly is almost pure binary so it is without bias the fastest language. – KKZiomek Jun 19 '16 at 04:31
  • 6
    C is the fastest because it's the speed of light, and relativity? – Meet Taraviya Jun 14 '17 at 13:51
  • 2
    It is of course wrong that C is the fastest program language. No program language of any kind comes near to the speed of FORTH. FORTH is used to trigger nuclear bombs, it is the program language on the most satellites, the main program language in the International Space Station and also in CERN and at ITER. I was comparing the speed between Microsoft C (different Versions) and FORTH. YAWN to C ... – Scoobeedo Cool Dec 18 '17 at 01:10
  • Please provide side by side comparison. I'll stay vague so as not to start a flame war, but there are reasons that other popular languages should outperform C. If you want to know **why** C is faster, you must first validate **that** C is faster. – Phillip Scott Givens May 24 '18 at 16:38
  • I don't think this question can really be made on-topic by current Stack Overflow standards; but with a bit of editing I think it could be objective enough to fit on the planned [Programming Language Design and Implementation](https://area51.stackexchange.com/proposals/127456/programming-language-design-and-implementation) Stack Exchange site (currently in the Commitment phase). – Karl Knechtel Feb 11 '23 at 17:24

33 Answers33

221

There isn't much that's special about C. That's one of the reasons why it's fast.

Newer languages which have support for garbage collection, dynamic typing and other facilities which make it easier for the programmer to write programs.

The catch is, there is additional processing overhead which will degrade the performance of the application. C doesn't have any of that, which means that there is no overhead, but that means that the programmer needs to be able to allocate memory and free them to prevent memory leaks, and must deal with static typing of variables.

That said, many languages and platforms, such as Java (with its Java Virtual Machine) and .NET (with its Common Language Runtime) have improved performance over the years with advents such as just-in-time compilation which produces native machine code from bytecode to achieve higher performance.

Sebastian Karlsson
  • 715
  • 1
  • 8
  • 19
coobird
  • 159,216
  • 35
  • 211
  • 226
  • 5
    garbage collection can be faster than manual memory management (for short-lived programs and/or plenty of memory). GC allows simple and fast allocation, and program doesn't spend time deallocating things. – Kornel Jan 26 '09 at 20:37
  • 2
    C programs generally allocate and deallocate memory on an as-needed basis. This is inefficient. A good VM will allocate and deallocate in large chunks, yielding large gains in performance in many cases. – skaffman Jun 13 '09 at 11:30
  • 68
    There's nothing preventing a C program from performing the same chunked allocation and garbage collection, aside from being "hard". – ephemient Jun 22 '09 at 21:18
  • Very well said, but likes Rob Allen said, C also provides less abstraction then Java or .NET, resulting in fewer translation (which is less true these day due to just-in-time (JIT) compilation like you said) – Gab Royer Jun 22 '09 at 21:36
  • 5
    porneL, manual management and sensible allocations will always outperform any GC system when used correctly and a lot of attention is given, you have absolute knowledge about your usage patterns, the GC does not, plus GC systems add overhead –  Aug 25 '13 at 07:31
  • @skaffman - if many small allocations are done in C, its common to use a memory-pool, or a memory-arena. – ideasman42 Jul 27 '14 at 04:16
  • @ideasman42 In fact some malloc allocations split memory into several fixed size pools for large medium and small allocations, taking a big chunk with mmap and then giving memory from there. – Vality Aug 01 '14 at 16:27
  • @eph It's not so much the (non-deterministic) garbage collection, that enables blazingly fast allocations. By and large, that's a corollary of a compacting heap implementation. That requires, that objects can freely move in memory, something that neither C nor C++ allow. I guess, a hypothetical C implementation *could* add an abstraction between pointer types and memory. Seeing that after decades of experience with C, memory allocations are still among the most expensive operations we commonly perform, is a strong indication, that a compacting heap may not just be "hard", but impossible. – IInspectable Jun 04 '20 at 08:17
  • "deal with static typing" - This makes it sound like static typing is a burden. I'd argue it's a feature since it allows you to detect many errors without running the program. – martinkunev Sep 15 '21 at 09:28
97

There is a trade-off the C designers have made. That's to say, they made the decision to put speed above safety. C won't

  • Check array index bounds
  • Check for uninitialized variable values
  • Check for memory leaks
  • Check for null pointer dereference

When you index into an array, in Java it takes some method call in the virtual machine, bound checking and other sanity checks. That is valid and absolutely fine, because it adds safety where it's due. But in C, even pretty trivial things are not put in safety. For example, C doesn't require memcpy to check whether the regions to copy overlap. It's not designed as a language to program a big business application.

But these design decisions are not bugs in the C language. They are by design, as it allows compilers and library writers to get every bit of performance out of the computer. Here is the spirit of C how the C Rationale document explains it:

C code can be non-portable. Although it strove to give programmers the opportunity to write truly portable programs, the Committee did not want to force programmers into writing portably, to preclude the use of C as a ``high-level assembler'': the ability to write machine-specific code is one of the strengths of C.

Keep the spirit of C. The Committee kept as a major goal to preserve the traditional spirit of C. There are many facets of the spirit of C, but the essence is a community sentiment of the underlying principles upon which the C language is based. Some of the facets of the spirit of C can be summarized in phrases like

  • Trust the programmer.
  • Don't prevent the programmer from doing what needs to be done.
  • Keep the language small and simple.
  • Provide only one way to do an operation.
  • Make it fast, even if it is not guaranteed to be portable.

The last proverb needs a little explanation. The potential for efficient code generation is one of the most important strengths of C. To help ensure that no code explosion occurs for what appears to be a very simple operation, many operations are defined to be how the target machine's hardware does it rather than by a general abstract rule. An example of this willingness to live with what the machine does can be seen in the rules that govern the widening of char objects for use in expressions: whether the values of char objects widen to signed or unsigned quantities typically depends on which byte operation is more efficient on the target machine.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    So in theory, you're saying that if another language had a "compile without safety net" option it could compile down to something as fast as C? – Mike C. Jan 07 '09 at 02:14
  • i don't say anything about logic rules like that :) but indeed every checks will slow down. when it's justified, checks are good. when it's not, then checks aren't the right thing. Also, performance depends on implementations. languages can only put burdens or give freedoms – Johannes Schaub - litb Jan 07 '09 at 02:18
  • 65
    C does check for null pointer deref by crashing violently :-). It also occasionally checks for out-of-range array indexes and uninitialized variables by screwing up your stack frames and data. Unfortunately it checks these at runtime. – paxdiablo Jan 07 '09 at 02:47
  • 26
    I wouldn't say that C isn't safe, which sounds like what you're hinting at. It assumes you aren't an idiot. If you point a gun down and shoot yourself in the foot, C will happily oblige and let you do that because it assumes you're smarter than it is. That's not necessarily a bad thing. – Bob Somers Jan 07 '09 at 05:42
  • 26
    @Bob: Exactly. Saying C isn't safe because it lets you do dangerous stuff is like saying a car isn't safe because it will let you drive off a cliff. C is as safe as the person doing the driving (but there are a lot of unsafe drivers out there). – Robert Gamble Jan 07 '09 at 05:53
  • 9
    Bob, making bugs like buffer overruns doesn't mean you're an idiot. It just means you are still human. I realize that C and C++ isn't *bad* (i very much like them). – Johannes Schaub - litb Jan 07 '09 at 11:14
  • 1
    I used the word "safe" in the same manner like in the C# word, when they talk about "unsafe" mode. can you hint a better word? – Johannes Schaub - litb Jan 07 '09 at 11:15
  • 4
    @pax: Actually, C doesn't check for that either. The OS/hardware does (unless you're on a machine where page 0 is writable; fluffing NULL handling there can be *very* interesting). – Donal Fellows Oct 27 '10 at 00:09
  • a C implementation is not *required* to check for those things, but it is *permitted* to. – mlp Jul 28 '11 at 02:04
  • 6
    "It's not designed as a language to program a big business application." - huh? BS, at best. What would you call all great business applications out there that are written in C? –  May 18 '13 at 20:08
  • 1
    @h2c i have not said that you cannot program great business applications with C...you can use a toothbrush to clean your floor perfectly clean. But it will be a pain in the ass because your brush is not designed for it. – Johannes Schaub - litb May 19 '13 at 14:34
  • 7
    @JohannesSchaub-litb C is perfect for large-scale application programming. If one finds it hard to make projects bigger than a hello world, then the problem is with the programmer, not with the language... –  May 19 '13 at 16:15
  • 1
    Regarding safety, there are runtime tests (ASan address-sanitizer, valgrind), these can help a lot in catching incorrect/unsafe use of C. So I don't think its totally fair to define C as unsafe - as a generalization. – ideasman42 Jul 27 '14 at 04:29
  • 2
    C and C++ are extremely unsafe. So much so that Mozilla created a whole new language (Rust) to be a safer replacement. Using C or C++ for any non-trivially-verifiable program that deals with potentially hostile input is one of the main causes of security exploits. People make too many mistakes fo "trust the programmer" to be a good answer. – Demi Sep 29 '15 at 07:54
  • This is probably the very best comment on this issue. In the end it is about the balance between how much control the language features give to the compiler vs the programmer. In C there are fewer abstractions and therefore fewer places for automation. The C++ standard has an embarrassment of rochness in this regard and hence thd potential to write code fast but with slower performance. Remember optisation will take liberties with your code. C allows you to even fine tune this and some times forces you. – cdcdcd Apr 17 '16 at 20:57
  • Nope, C doesn't check for NULL pointer, it doesn't do anything to crash violently or smoothly or to crash at all! Rather those are properties of the underlying system. On a system that has some hardware memory management features (a MMU), the systems often configures it so that an access to the address 0 provoques a hardware interrupt, that is then processed by the kernel and used to send a SIGSEG signal to the application. But on other hardware or with other systems, you could very well read or even write to the address 0, and C would do nothing to prevent you doing just that. – informatimago Jul 07 '16 at 08:58
  • not sure on widening chars, seems more cultural than hardware... unix has signed chars, Windows has unsigned. – Jasen Jan 11 '17 at 20:25
  • The compiler shouldn't trust the programmer. The programmer shouldn't trust itself. There's must be mechanisms to avoid errors. This is basic engineering. – Luiz Felipe Nov 24 '19 at 00:08
  • @LuizFelipe "The programmer shouldn't trust itself [sic]" Yes, absolutely. "The compiler shouldn't trust the programmer" No. The compiler is the tool that the programmer uses, and as such, it should not think it's smarter than its master. The tool may try to help its master in writing good code, but when the master says "trust me!", the tool should do so. If that trust was misplaced, well, then the master is to be blamed. The tool is only to blame if it doesn't do it's master's wish. – cmaster - reinstate monica Feb 24 '20 at 16:11
  • "trust me" famous last words before losing fingers to the angle grinder circular saw. -------- C language is: lets put a circular saw in a angle grinder and hang it from the ceiling, also it's always powered. – Luiz Felipe Mar 04 '20 at 14:48
  • In any endeavor, there's a tradeoff between asking people to be careful, versus putting in safeguards to protect them if they goof. Once upon a time, construction workers were supposed to be careful not to fall out of unfinished buildings; today, OSHA says you have to put up temporary railings. C has relatively few built-in safeguards, so by 21st century software engineering standards, it is relatively unsafe. (By 1970's standards, and to this day by those of us who still love it, it's fine.) – Steve Summit Jan 22 '21 at 21:09
80

If you spend a month to build something in C that runs in 0.05 seconds, and I spend a day writing the same thing in Java, and it runs in 0.10 seconds, then is C really faster?

But to answer your question, well-written C code will generally run faster than well-written code in other languages because part of writing C code "well" includes doing manual optimizations at a near-machine level.

Although compilers are very clever indeed, they are not yet able to creatively come up with code that competes with hand-massaged algorithms (assuming the "hands" belong to a good C programmer).

Edit:

A lot of comments are along the lines of "I write in C and I don't think about optimizations."

But to take a specific example from this post:

In Delphi I could write this:

function RemoveAllAFromB(a, b: string): string;
var
  before, after :string;
begin
  Result := b;
  if 0 < Pos(a,b) then begin
    before := Copy(b,1,Pos(a,b)-Length(a));
    after := Copy(b,Pos(a,b)+Length(a),Length(b));
    Result := before + after;
    Result := RemoveAllAFromB(a,Result);  //recursive
  end;
end;

and in C I write this:

char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
   for (j = 0; j < len2; j++) {
     if (s1[i] == s2[j]) {
       break;
     }
   }
   if (j == len2) {  /* s1[i] is not found in s2 */
     *result = s1[i]; 
     result++; /* assuming your result array is long enough */
   }
}

But how many optimizations are there in the C version? We make lots of decisions about implementation that I don't think about in the Delphi version. How is a string implemented? In Delphi I don't see it. In C, I've decided it will be a pointer to an array of ASCII integers, which we call chars. In C, we test for character existence one at a time. In Delphi, I use Pos.

And this is just a small example. In a large program, a C programmer has to make these kinds of low-level decisions with every few lines of code. It adds up to a hand-crafted, hand-optimized executable.

Community
  • 1
  • 1
JosephStyons
  • 57,317
  • 63
  • 160
  • 234
  • 55
    To be fair though, there isn't much that would take one month in C that would take only one day in Java that only takes 0.05 seconds to execute (i.e. small program). – dreamlax Jan 07 '09 at 02:57
  • Your first point is a good one, it generally takes longer to program in C because it doesn't include the language and library facilities that so many newer languages have that help to make a programmer so productive. I do *not* agree with the rest of your post though. – Robert Gamble Jan 07 '09 at 03:39
  • 21
    I have programmed in C for years and almost never have to do any of the kinds of the optimizations you hint at. I have ported a number of programs to C (mainly from Perl) and generally see a 10x plus speed increase and significant reduction in memory usage without any hand-coded optimizations. – Robert Gamble Jan 07 '09 at 03:40
  • 1
    Of course there are some things that can take considerably longer to program in C due to lack of existing facilities so it is a tradeoff between computer performance and programmer performance (among other things) which is why we don't all program everything in C. – Robert Gamble Jan 07 '09 at 03:40
  • 4
    I've created C++ programs that process thousands of lines of data in less time then Java or .NET programs can start up. It is one of the frustrations that I have with the more modern languages. C is great for lean programs that need minimal runtime requirements. PowerBasic is great for that also. – bruceatk Jan 07 '09 at 04:05
  • I think there is in this answer and its comments a fundamental lack of understanding of just what the drawbacks of C programming are. Yes, it will take a bit of additional overhead to create a complicated application. This is no different from the overhead necessary to build complicated objects. – Max Jan 07 '09 at 05:24
  • 1
    You're mixing coding time with execution time. It seems that the OP is concerned with execution time. I haven't done any optimization that you speak of, and C would easily blow away Java or other lang. (Java being the one that I've crudely tested) – Calyth Jan 08 '09 at 18:57
  • or you can use strchr instead of inner loop, thus achieving even better optimization by using CPU's support for array scanning. No, I don't think I'd write your code sample this way. Then again, I am a C++ programmer, not C. –  Jan 13 '09 at 20:42
  • I would also say that this is badly written Delphi code. Most issues with code speed are algorithmic and not execution. The Delphi code doesn't actually do the job correctly (it should look for any character in B, not the whole string), and it's O(N^3) versus O(N^2) for the C code. – Orion Adrian Feb 06 '09 at 19:21
  • @RobertGamble I spent the last 3 years reading it. I think I get it now. He argues that, while C is a difficult language, designing "objects" properly (in object-oriented languages) is hard too, so this is not C's disadvantage. He doesn't explain what it is. I'm finally free. – MaiaVictor Mar 30 '13 at 06:44
  • 48
    You're saying a program that takes a month in C and is twice as fast as a program written in Java that takes only day to write isn't worthwhile? What if that program needs to run 500,000,000+ times a day? Being twice as fast is incredibly significant. If it runs on thousands or millions of CPUs, the cost savings of the extra month of development to achieve twice the performance will be enormous. Basically, you have to know/understand the scale of your deployment before you choose the development platform. – nicerobot Jun 29 '14 at 17:30
  • 1
    In these discussions people often overlook that C often doesn't exist on its own, Use it where speed is important, and write extensions for other languages (scripting languages for example) if you only need specific areas to be performant. – ideasman42 Jul 27 '14 at 04:25
  • 1
    Even considering what you are saying is true with respect to time if your application is extremely time sensitive, i.e. every nanosecond counts e.g. in gps systems, I would say one would have to take a month and write the code in C then. – ITguy Jan 28 '16 at 10:58
54

I didn't see it already, so I'll say it: C tends to be faster because almost everything else is written in C.

Java is built on C, Python is built on C (or Java, or .NET, etc.), Perl is, etc. The OS is written in C, the virtual machines are written in C, the compilers are written in C, the interpreters are written in C. Some things are still written in Assembly language, which tends to be even faster. More and more things are being written in something else, which is itself written in C.

Each statement that you write in other languages (not Assembly) is typically implemented underneath as several statements in C, which are compiled down to native machine code. Since those other languages tend to exist in order to obtain a higher level of abstraction than C, those extra statements required in C tend to be focused on adding safety, adding complexity, and providing error handling. Those are often good things, but they have a cost, and its names are speed and size.

Personally, I have written in literally dozens of languages spanning most of the available spectrum, and I personally have sought the magic that you hint at:

How can I have my cake and eat it, too? How can I play with high-level abstractions in my favorite language, then drop down to the nitty gritty of C for speed?

After a couple of years of research, my answer is Python (on C). You might want to give it a look. By the way, you can also drop down to Assembly from Python, too (with some minor help from a special library).

On the other hand, bad code can be written in any language. Therefore, C (or Assembly) code is not automatically faster. Likewise, some optimization tricks can bring portions of higher-level language code close to the performance level of raw C. But, for most applications, your program spends most of its time waiting on people or hardware, so the difference really does not matter.

Enjoy.

Rob Williams
  • 7,919
  • 1
  • 35
  • 42
  • 11
    This doesn't really apply to JIT-compiled languages. It's not like my C# is being compiled to IL which is translated into C which is compiled to machine code. No, the IL is JIT-compiled - and the implementation language of the JIT is irrelevant at that point. It's just producing machine code. – Jon Skeet Jan 07 '09 at 07:30
  • 4
    God forbid that I should question the legendary Jon Skeet, but it does seem entirely relevant that the machine code being produced is for C# instead of C, so it is "higher level", has more functionality, has safety checks, etc. and will be, therefore, slower than the "equivalent" C. – Rob Williams Jan 07 '09 at 17:22
  • 3
    @Jon: I was about to say something similar but the point is actually somewhat valid because a lot of the .NET library core components are actually really written in C and thus have C's speed limitations. It will be interesting to see how this will change in the future. – Konrad Rudolph Jan 08 '09 at 22:00
  • 1
    This seems the wrong way around, other language compiler/interpreter/vms are frequently but not always written in c(or at least for the lowest layer) because c is pretty fast(and in many cases the fastest). – Roman A. Taycher Apr 16 '10 at 11:24
  • @KonradRudolph Is it still valid for the new roselyn compiler? – EProgrammerNotFound Jul 17 '15 at 01:33
  • @EProgrammerNotFound Good question, and I have no idea. They have probably moved away from C quite a bit. – Konrad Rudolph Jul 17 '15 at 08:38
  • 3
    This answer is not true. As pointed out above, it doesn't apply for JIT languages, but also it doesn't apply for languages with their own compilers too (which, if extraordinary effort were put into them, could generate faster code than modern C compilers). The only other class of languages left is interpreted languages, and those are not slower than C *only* because they're written in C themselves, but because the overhead of interpreting, no matter how you slice it and even if the interpreter was written in assembly, is huge. – Score_Under Jan 17 '16 at 04:36
  • C compilers are written in C. Does that make C faster than C? – MMa Jun 14 '17 at 22:10
  • Actually, Java's JVM and C#'s CLR are mostly implemented in C++, so is GCC ;). – dvr33 Dec 19 '19 at 15:11
39

There are a lot of questions in there - mostly ones I am not qualified to answer. But for this last one:

what's to stop other languages from being able to compile down to binary that runs every bit as fast as C?

In a word, abstraction.

C is only one or two levels of abstraction away from machine language. Java and the .NET languages are at a minimum three levels of abstraction away from assembler. I'm not sure about Python and Ruby.

Typically, the more programmer toys (complex data types, etc.), the further you are from machine language and the more translation has to be done.

I'm off here and there, but that's the basic gist.

There are some good comments on this post with more details.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rob Allen
  • 17,381
  • 5
  • 52
  • 70
  • 3
    Technically, Java and .Net are infinitely abstracted away from the machine language of the machine they run on. They run in VMs. Even with JIT the original code has to be massively massaged to get something resembling the native machine code. – jmucchiello Jan 07 '09 at 03:34
  • 1
    .net code does not run in a VM. It runs as native instructions on whatever processor platform it's running on (32-bit x86, 64-bit x86, or IA64). – Robert C. Barth Jan 07 '09 at 05:22
  • 11
    @Robert: .net *does* use a VM. .net code is compiled into bytecode which is executed by the VM. The VM converts the bytecode into native instructions at run time. – Robert Gamble Jan 07 '09 at 05:43
  • 3
    It's _very_ important to note that Java and other OO language abstractions have affected processor instruction sets. Newer processors have instructions that make Java run faster if the java VM knows about these optimizations and uses them. It's not huge, but it's helpful. – Adam Davis Jan 08 '09 at 20:54
  • @Adam: What instructions are you thinking of? (asking not challenging, I'm unfamiliar) – Joseph Garvin Aug 08 '09 at 20:04
  • 1
    Maybe ThumbEE http://en.wikipedia.org/wiki/ARM_architecture#Thumb_Execution_Environment_.28ThumbEE.29 – Roman A. Taycher Apr 16 '10 at 11:19
  • @RobertGamble Yes, once (per run). After that the native code will always be executed, you can also use ngen.exe to compile the il to native code. Anyway, when using native code, you are bound to the compiler and because of it, could be possible that a c# code gets to run faster than a c code. The JIT will always compile using the lastest, therefore probably fastest (think of MMX, SSE, SSE2...) instructions – EProgrammerNotFound Jul 16 '15 at 05:01
  • @JosephGarvin In .net you can write once and with the flag AnyCPU. Allowing your code to be executed in both x86 and x64 machines. For a c written program targetting x86, if you run your app in windows, for instance, your native code would be running in WoW and would made use of less registers, olders floating points facilities, etc. Net apps would compile targeting the x64 platform, therefore it would use the most newer instructions. All of this depends of the code written, though. – EProgrammerNotFound Jul 16 '15 at 05:13
  • I agree that Java and .NET are higher level languages, but I don't think you can measure abstraction in terms of natural numbers. It's simply a relative scale, the numbers mislead one to think that there's a more rigorous measure of "level of abstraction". – NJay Nov 29 '21 at 00:57
  • I don't feel that this answer really "nails it". Compared to some languages it is certainly true. However, C's closest neighbour is C++ which has the mantra "abstraction at no cost" which it does very well (at the cost of expressive complexity). So I think that it's important to stress that carefully curated abstractions do not necessarily make a language "slow". – Terry Burton Dec 13 '21 at 21:10
37

It is not so much that C is fast as that C's cost model is transparent. If a C program is slow, it is slow in an obvious way: by executing a lot of statements. Compared with the cost of operations in C, high-level operations on objects (especially reflection) or strings can have costs that are not obvious.

Two languages that generally compile to binaries which are just as fast as C are Standard ML (using the MLton compiler) and Objective Caml. If you check out the benchmarks game you'll find that for some benchmarks, like binary trees, the OCaml version is faster than C. (I didn't find any MLton entries.) But don't take the shootout too seriously; it is, as it says, a game, the the results often reflect how much effort people have put in tuning the code.

igouy
  • 2,547
  • 17
  • 16
Norman Ramsey
  • 198,648
  • 61
  • 360
  • 533
20

C is not always faster.

C is slower than, for example, Modern Fortran.

C is often slower than Java for some things (especially after the JIT compiler has had a go at your code).

C lets pointer aliasing happen, which means some good optimizations are not possible. Particularly when you have multiple execution units, this causes data fetch stalls. Ow.

The assumption that pointer arithmetic works really causes slow bloated performance on some CPU families (PIC particularly!) It used to suck the big one on segmented x86.

Basically, when you get a vector unit, or a parallelizing compiler, C stinks and modern Fortran runs faster.

C programmer tricks, like thunking (modifying the executable on the fly), cause CPU prefetch stalls.

Do you get the drift?

And our good friend, the x86, executes an instruction set that these days bears little relationship to the actual CPU architecture. Shadow registers, load-store optimizers, all in the CPU. So C is then close to the virtual metal. The real metal, Intel don't let you see. (Historically VLIW CPU's were a bit of a bust so, maybe that's no so bad.)

If you program in C on a high-performance DSP (maybe a TI DSP?), the compiler has to do some tricky stuff to unroll the C across the multiple parallel execution units. So in that case, C isn't close to the metal, but it is close to the compiler, which will do whole program optimization. Weird.

And finally, some CPUs (www.ajile.com) run Java bytecodes in hardware. C would a PITA to use on that CPU.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tim Williscroft
  • 3,705
  • 24
  • 37
  • 1
    When was the last time thunking has been written, in C? Modern x86 is an interface to a mostly RISC design, but that has little to do with VLIW... – Calyth Jan 08 '09 at 19:05
  • 8
    Much of your post ignores the existance of C99. Also, many C/C++ compilers offer the C99 restrict keyword (ensures no pointer aliasing) as an extension. – Evan Teran Jan 13 '09 at 20:25
  • I assume that everyone is following/transitioning to following the CWE/SANS top 25 and avoiding making new designs in C. So no green-fields C, so little to no C99. – Tim Williscroft Jan 20 '09 at 03:37
  • 2
    Could you show example when c is slower than modern Fortenberry? – Adam Jan 26 '16 at 17:56
  • I'm not sure there has ever been a time when C compilers competed very well with the best Fortran compilers. Of course there's a lot of code you would not want to write in FORTRAN 77 (let alone 66), but more recent Fortran standards have been increasingly pleasant. –  Aug 30 '16 at 21:57
  • 2019, and I'm currently working on a project that creates a new library written in C99... It's true that the aliasing problem may lead Fortran code to execute faster than the no `restrict` C version, but that's about it. Fortran is a true PITA for other reasons, though, you absolutely do not want to write any new code in that **** of a language. But C is alive and well today, and I guess we will still see new C projects in 2069. – cmaster - reinstate monica Feb 24 '20 at 16:30
  • The Ajile link is (effectively) broken: *"The domain Ajile.com may be for sale."* – Peter Mortensen Feb 11 '23 at 16:30
12

what's to stop other languages from being able to compile down to binary that runs every bit as fast as C?

Nothing. Modern languages like Java or .NET languages are oriented more toward programmer productivity rather than performance. Hardware is cheap nowadays. Also compilation to intermediate representation gives a lot of bonuses such as security, portability, etc. The .NET CLR can take advantage of different hardware. For example, you don't need to manually optimize/recompile program to use the SSE instructions set.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
aku
  • 122,288
  • 32
  • 173
  • 203
  • i would argue the portability here. If you want really portable code you will write it in C and not in any other language. We have a code running on about 25 operating systems. Starting from dos and threadX and finishing on Linux/XP show me another language that can do that :) – Ilya Jan 07 '09 at 07:49
  • 1
    @Ilya I disagree. It's just as easy to write non-portable code in C. Look at how painful it was for some to port to 64-bit. Bytecode langauges could work across platform if you've got the right bytecode interpreter. – Calyth Jan 08 '09 at 19:02
  • 1
    @IIya, portable C code is an exeption rather than rule, I ported C code between different hardware/software platforms and know that it is a nightmare. – aku Jan 09 '09 at 07:07
  • Even for PC word it is not the case. Look in to reality most of cross platform application written in c/c++, a little bit in java. For embedded low level development there is just no another cases. C is most portable language de facto. – Ilya Jan 12 '09 at 11:41
  • @aku -> PORTING bad code might be disaster i agree. Writing portable code in ADVANCE - C is a best choice. I would say C++ is an option but going to embedded platform you always will find decent C compiler, for c++ you might find you self without compiler. – Ilya Jan 12 '09 at 11:43
  • ilya, I have pretty good experience in writing C/C++ code for embedded (cell phones) and desktop apps. There are too much details you need to take into account when targeting multiple platforms. Managed code eliminates most of this problem. – aku Jan 12 '09 at 14:19
  • Also I can assure you that choice of C is not dictated but it's portability. In most cases you just can't afford having virtual machine/don't have appropriate compiler. For example modern Android OS uses Java as an application language. – aku Jan 12 '09 at 14:21
  • Ok i don't assume that anyone should write a game for mobile phone in C obviously. But i do assume that flash/sdio driver, network stack etc ... will be written in C and will portable across numerous OS's and only in C. – Ilya Jan 12 '09 at 14:52
  • And i know that Symbian for example written in C++, but if you will have a chance to look (i did) into low level source code you will find a bunch of static C function wrapped into classes. – Ilya Jan 12 '09 at 14:53
  • Ilya, yes when you're working on low-level (sdio driver in your example, etc) you're pretty much limited in your choice, but when you have a luxury of hardware abstraction level then there are better alternatives to C/C++ – aku Jan 12 '09 at 15:14
  • for portable gui what be your choice ? Main will be QT :) – Ilya Jan 12 '09 at 15:25
  • WinForms (Windows, *NIX, MacOS) :) Unfortunately can't be used in some mobile OS – aku Jan 12 '09 at 16:57
  • although it does not suite embedded enviroment i will mark this one for the future. By the way really portable library http://swellsoftware.com/products/ , but to simple for desktop development :) – Ilya Jan 12 '09 at 19:13
  • Java and .NET have different semantics from C, and it's unproven whether or not they give enough information to the compiler for it to optimize as well as C in all cases. If this were a solved problem, garbage collectors would always beat manual memory management, which isn't the case (yet). – Joseph Garvin Jan 14 '09 at 03:03
  • Joseph, Java and .NET give you abstraction layer that allows managed program to be more efficient than native in some cases. Also it is hard to beat GC in medium/large project. Time necessary to debug hand crafted mem management often doesn't worse performance gain. – aku Jan 19 '09 at 14:16
11

I guess you forgot that Assembly language is also a language :)

But seriously, C programs are faster only when the programmer knows what he's doing. You can easily write a C program that runs slower than programs written in other languages that do the same job.

The reason why C is faster is because it is designed in this way. It lets you do a lot of "lower level" stuff that helps the compiler to optimize the code. Or, shall we say, you the programmer are responsible for optimizing the code. But it's often quite tricky and error prone.

Other languages, like others already mentioned, focus more on productivity of the programmer. It is commonly believed that programmer time is much more expensive than machine time (even in the old days). So it makes a lot of sense to minimize the time programmers spend on writing and debugging programs instead of the running time of the programs. To do that, you will sacrifice a bit on what you can do to make the program faster because a lot of things are automated.

PolyThinker
  • 5,152
  • 21
  • 22
  • 4
    Although if you wrote a program once in C and again in Assembly, the C version would probably be faster because the compiler is smarter than you are. – mk12 Aug 07 '12 at 22:25
9

The main factors are that it's a statically-typed language and that's compiled to machine code. Also, since it's a low-level language, it generally doesn't do anything you don't tell it to.

These are some other factors that come to mind.

  • Variables are not automatically initialized
  • No bounds checking on arrays
  • Unchecked pointer manipulation
  • No integer overflow checking
  • Statically-typed variables
  • Function calls are static (unless you use function pointers)
  • Compiler writers have had lots of time to improve the optimizing code. Also, people program in C for the purpose of getting the best performance, so there's pressure to optimize the code.
  • Parts of the language specification are implementation-defined, so compilers are free to do things in the most optimal way

Most static-typed languages could be compiled just as fast or faster than C though, especially if they can make assumptions that C can't because of pointer aliasing, etc.

Matthew Crumley
  • 101,441
  • 24
  • 103
  • 129
  • C low-level ? I guess it's a relative meaning now, compared to Java yes but compared to assembly no. Good post, got me thinking. – Mark Jan 07 '09 at 03:23
  • You're right, it's definitely relative. What I mean is that it's "close to the machine" and doesn't help you do things like memory management or keeping track of array sizes. – Matthew Crumley Jan 07 '09 at 04:05
  • 2
    C is a low-level language. C has always been a low-level language. You hand-translate C code into the assembler without much difficulty. – Robert C. Barth Jan 07 '09 at 05:25
  • 4
    @Robert: C used to be considered a high-level language because compared to assembly (which was very common), it was. It is considered a low-level language in comparison to the majority of languages in use today. – Robert Gamble Jan 07 '09 at 05:56
  • Honestly, this is a very biased answer. Damn near all C programmers do bounds checking, etc. Yet C is still MUCH faster than C++. – MarcusJ Jun 16 '16 at 08:14
9

C++ is faster on average (as it was initially, largely a superset of C, though there are some differences). However, for specific benchmarks, there is often another language which is faster.

From The Computer Language Benchmarks Game:

fannjuch-redux was fastest in Scala

n-body and fasta were faster in Ada.

spectral-norm was fastest in Fortran.

reverse-complement, mandelbrot and pidigits were fastest in ATS.

regex-dna was fastest in JavaScript.

chameneou-redux was fastest is Java 7.

thread-ring was fastest in Haskell.

The rest of the benchmarks were fastest in C or C++.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • "as it is a super set of C" - No, C++ is *not* a superset of C. – P.P Jul 19 '16 at 14:58
  • @P.P. Are you saying `extern "C"` not longer works in C++? – Peter Lawrey Jul 19 '16 at 15:02
  • 1
    `extern "C"` has nothing to do with C++ being a *superset* of C. – P.P Jul 19 '16 at 15:05
  • 1
    @P.P. With `extern "C"` you can write anything you can write in C you can write in C++ and `extern "C"` is part of C++. – Peter Lawrey Jul 19 '16 at 15:09
  • 2
    It's like saying `system("bash script.sh");` works for any bash script, and hence C is a superset of bash. `extern "C"` provides the C linkage in C++ due to name mangling. Whereas calling X as a superset of Y means anything that can be done in Y can also be done in X, which is not true of C++. There are quite a few language constructs that are valid in C but not in C++. – P.P Jul 19 '16 at 15:14
  • 1
    @P.P. There is nothing in the C++ standard which mandates that `bash` is an available command line program. If it did and included what version/specification of bash needed to be supported, I would consider it s superset. – Peter Lawrey Jul 19 '16 at 15:17
  • 1
    it's trivially easy to write C code that is not C++ code, eg `struct foo { int: this; }; typedef float foo;` – Jasen Jan 11 '17 at 20:53
  • 1
    "No, C++ is not a superset of C. " pedantically no. For all other intents and purposes, it is, even if you can write contrived constructs in one that don't work in the other. – Hejazzman Mar 28 '19 at 23:31
7

Many of these answers give valid reasons for why C is, or is not, faster (either in general or in specific scenarios). It's undeniable that:

  • Many other languages provide automatic features that we take for granted. Bounds checking, run-time type checking, and automatic memory management, for example, don't come for free. There is at least some cost associated with these features, which we may not think about—or even realize—while writing code that uses these features.
  • The step from source to machine is often not as direct in other languages as it is in C.
  • OTOH, to say that compiled C code executes faster than other code written in other languages is a generalization that isn't always true. Counter-examples are easy to find (or contrive).

All of this notwithstanding, there is something else I have noticed that, I think, affects the comparative performance of C vs. many other languages more greatly than any other factor. To wit:

Other languages often make it easier to write code that executes more slowly. Often, it's even encouraged by the design philosophies of the language. Corollary: a C programmer is more likely to write code that doesn't perform unnecessary operations.

As an example, consider a simple Windows program in which a single main window is created. A C version would populate a WNDCLASS[EX] structure which would be passed to RegisterClass[Ex], then call CreateWindow[Ex] and enter a message loop. Highly simplified and abbreviated code follows:

WNDCLASS wc;
MSG      msg;

wc.style         = 0;
wc.lpfnWndProc   = &WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = NULL;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = "MainWndCls";

RegisterClass(&wc);

CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

while(GetMessage(&msg, NULL, 0, 0)){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

An equivalent program in C# could be just one line of code:

Application.Run(new Form());

This one line of code provides all of the functionality that nearly 20 lines of C code did, and adds some things we left out, such as error checking. The richer, fuller library (compared to those used in a typical C project) did a lot of work for us, freeing our time to write many more snippets of code that look short to us but involve many steps behind the scenes.

But a rich library enabling easy and quick code bloat isn't really my point. My point is more apparent when you start examining what actually happens when our little one-liner actually executes. For fun sometime, enable .NET source access in Visual Studio 2008 or higher, and step into the simple one-linef above. One of the fun little gems you'll come across is this comment in the getter for Control.CreateParams:

// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
// 
if (createParams == null) {
    createParams = new CreateParams(); 
} 

Ten times. The information roughly equivalent to the sum of what's stored in a WNDCLASSEX structure and what's passed to CreateWindowEx is retrieved from the Control class ten times before it's stored in a WNDCLASSEX structure and passed on to RegisterClassEx and CreateWindowEx.

All in all, the number of instructions executed to perform this very basic task is 2–3 orders of magnitude more in C# than in C. Part of this is due to the use of a feature-rich library, which is necessarily generalized, versus our simple C code which does exactly what we need and nothing more. But part of it is due to the fact that the modularized, object-oriented nature of .NET framework, lends itself to a lot of repetition of execution that often is avoided by a procedural approach.

I'm not trying to pick on C# or the .NET framework. Nor am I saying that modularization, generalization, library/language features, OOP, etc. are bad things. I used to do most of my development in C, later in C++, and most lately in C#. Similarly, before C, I used mostly assembly. And with each step "higher" my language goes, I write better, more maintainable, more robust programs in less time. They do, however, tend to execute a little more slowly.

P Daddy
  • 28,912
  • 9
  • 68
  • 92
  • 2
    That is an API issue, not a language issue. – Arafangion May 14 '10 at 04:47
  • 2
    @Arafangion: I understand what you're saying, but it kind of misses the point. The feature-rich library is enabled (and, in a way, demanded) by the feature-rich language. And it's not just the library. The library is just an example of common usage of the language. Typical application code in any language generally bears a resemblance to the libraries typically used in that language. It's really more of a mindset fostered by the language. For example, OO languages generally spend more time allocating, constructing, destructing, and deallocating objects than languages with less OOP support do. – P Daddy May 14 '10 at 20:11
  • I'll concede that a given choice of language generally implies a particular platform and library, which is why I made that comment (so that the reader would be more aware), but that said, using (for example) C++ on windows is a very different beast to, say, C++ on linux and different again with C++ on Android. Another example is Python - we have CPython, Jython, PyPy, and IronPython - all of which use very different libraries. – Arafangion May 15 '10 at 13:02
  • But using any of these Pythons, developers will tend to write applications a certain way. For example, they may read and write from a text file, creating new objects with the data they read. In C, on the other hand, a developer would more likely do a one-time allocation of an array of structs, and read and write those structs from a binary file. This is, of course, simply a contrived example that attempts to illustrate the point I'm trying to make about *mindset*. – P Daddy May 15 '10 at 23:07
7

For the most part, every C instruction corresponds to a very few assembler instructions. You are essentially writing higher level machine code, so you have control over almost everything the processor does. Many other compiled languages, such as C++, have a lot of simple looking instructions that can turn into much more code than you think it does (virtual functions, copy constructors, etc..) And interpreted languages like Java or Ruby have another layer of instructions that you never see - the Virtual Machine or Interpreter.

AShelly
  • 34,686
  • 15
  • 91
  • 152
  • And some of these high-level languages pride themselves in that they are able to remove most of the cruft they added in the first place. Things like copy elision, return value optimization, move construction/assignment, etc. in C++. – cmaster - reinstate monica Feb 24 '20 at 16:39
  • So it all comes down to the number of assembly instructions generated from the code. There more assembly instructions per line of high level code, the more the performance suffers? – ENDEESA May 10 '20 at 12:01
  • That might be an oversimplification, but there is a direct relationship between number of assembly instructions and program speed. There is a minimum amount of time for the processor to execute each instruction. IMHO, a language which lets you easily understand how many instructions you are writing helps you write more efficient code. ( There are other processor time costs, like branching and cache misses, but even there, less abstraction helps make it clear what the CPU is doing). – AShelly May 11 '20 at 18:10
7

I know plenty of people have said it in a long winded way, but:

C is faster because it does less (for you).

Dominik Grabiec
  • 10,315
  • 5
  • 39
  • 45
6

I don't think anyone has mentioned the fact that much more effort has been put into C compilers than any other compiler, with perhaps the exception of Java.

C is extremely optimizable for many of the reasons already stated - more than almost any other language. So if the same amount of effort is put into other language compilers, C will probably still come out on top.

I think there is at least one candidate language that, with effort, could be optimized better than C and thus we could see implementations that produce faster binaries. I'm thinking of Digital Mars' D, because the creator took care to build a language that could potentially be better optimized than C. There may be other languages that have this possibility. However, I cannot imagine that any language will have compilers more than just a few percent faster than the best C compilers. I would love to be wrong.

I think the real "low hanging fruit" will be in languages that are designed to be easy for humans to optimize. A skilled programmer can make any language go faster, but sometimes you have to do ridiculous things or use unnatural constructs to make this happen. Although it will always take effort, a good language should produce relatively fast code without having to obsess over exactly how the program is written.

It's also important (at least to me) that the worst case code tends to be fast. There are numerous "proofs" on the web that Java is as fast or faster than C, but that is based on cherry picking examples.

I'm not big fan of C, but I know that anything I write in C is going to run well. With Java, it will "probably" run within 15% of the speed, usually within 25%, but in some cases it can be far worse. Any cases where it's just as fast or within a couple of percent are usually due to most of the time being spent in the library code which is heavily optimized C code anyway.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Don
  • 61
  • 1
  • 1
  • [D](https://en.wikipedia.org/wiki/D_(programming_language)) didn't take off. [Rust](https://en.wikipedia.org/wiki/Rust_%28programming_language%29) may be the next contender. – Peter Mortensen Feb 11 '23 at 17:22
5

This is actually a bit of a perpetuated falsehood. While it is true that C programs are frequently faster, this is not always the case, especially if the C programmer isn't very good at it.

One big glaring hole that people tend to forget about is when the program has to block for some sort of I/O, such as user input in any GUI program. In these cases, it doesn't really matter what language you use since you are limited by the rate at which data can come in rather than how fast you can process it. In this case, it doesn't matter much if you are using C, Java, C# or even Perl; you just cannot go any faster than the data can come in.

The other major thing is that using garbage collection (GC) and not using proper pointers allows the virtual machine to make a number of optimizations not available in other languages. For instance, the JVM is capable of moving objects around on the heap to defragment it. This makes future allocations much faster since the next index can simply be used rather than looking it up in a table. Modern JVMs also don't have to actually deallocate memory; instead, they just move the live objects around when they GC and the spent memory from the dead objects is recovered essentially for free.

This also brings up an interesting point about C and even more so in C++. There is something of a design philosophy of "If you don't need it, you don't pay for it." The problem is that if you do want it, you end up paying through the nose for it. For instance, the vtable implementation in Java tends to be a lot better than C++ implementations, so virtual function calls are a lot faster. On the other hand, you have no choice but to use virtual functions in Java and they still cost something, but in programs that use a lot of virtual functions, the reduced cost adds up.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
James
  • 2,050
  • 13
  • 15
  • 1
    "the vtable implementation in Java tends to be a lot better than C++ implementations, so virtual function calls are a lot faster.". How on earth can you go faster than MOV EAX, [ECX]; CALL [EAX+someindex]; ? Unless you can call a function without looking it up, this looks pretty optimal. – Frans-Willem Jan 08 '09 at 21:55
  • @Frans - a JIT compiler (such as Java HotSpot) can inline the vtable lookup if it determines a given object is always of a given type. C++ will also do this if it knows the same info at compile-time, but it is easier to do this optimization with Java bytecode than with x86 machine instructions. – Tom Jan 14 '09 at 05:19
  • 6
    @James - Arguing "I/O makes performance matter less" doesn't invalidate the statement "C is faster than other languages". That's not a glaring hole, that's a strawman argument. – Tom Jan 14 '09 at 05:20
  • It would have been better to have used C's string handling (and also the standard C library's) as an example, as that's an area where C is poor. Most other languages do better, even with simplistic starting code. – Donal Fellows Oct 27 '10 at 00:59
  • @DonalFellows the mem* functions can be faster than the str* functions on some tasks, but string handling is efficient if care is taken. have you got a specific benchmark in mind? – Jasen Jan 11 '17 at 20:59
4

It's not so much about the language as the tools and libraries. The available libraries and compilers for C are much older than for newer languages. You might think this would make them slower, but au contraire.

These libraries were written at a time when processing power and memory were at a premium. They had to be written very efficiently in order to work at all. Developers of C compilers have also had a long time to work in all sorts of clever optimizations for different processors. C's maturity and wide adoption makes for a signficant advantage over other languages of the same age. It also gives C a speed advantage over newer tools that don't emphasize raw performance as much as C had to.

Dave Swersky
  • 34,502
  • 9
  • 78
  • 118
4

The lack of abstraction is what makes C faster. If you write an output statement you know exactly what is happening. If you write an output statement in Java it is getting compiled to a class file which then gets run on a virtual machine, introducing a layer of abstraction.

The lack of object-oriented features as a part of the language also increases its speed do to less code being generated. If you use C as an object-oriented language, then you are doing all the coding for things such as classes, inheritance, etc. This means rather than make something generalized enough for everyone with the amount of code and the performance penalty that requires you only write what you need to get the job done.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jared
  • 39,513
  • 29
  • 110
  • 145
4

Amazing to see the old "C/C++ must be faster than Java because Java is interpreted" myth is still alive and kicking. There are articles going back a few years, as well as more recent ones, that explain with concepts or measurements why this simply isn't always the case.

Current virtual machine implementations (and not just the JVM, by the way) can take advantage of information gathered during program execution to dynamically tune the code as it runs, using a variety of techniques:

  • rendering frequent methods to machine code,
  • inlining small methods,
  • adjustment of locking

and a variety of other adjustments based on knowing what the code is actually doing, and on the actual characteristics of the environment in which it's running.

joel.neely
  • 30,725
  • 9
  • 56
  • 64
  • 1
    I agree that Java has made significant performance improvements over the last few years that bring it much closer to C in terms of raw performance but it will take a while to live down the fact that it was *so* slow for *so* long. But who was talking about Java anyway? – Robert Gamble Jan 07 '09 at 03:47
  • Java is an "other language" referenced by the OP, is it not? – Robert C. Barth Jan 07 '09 at 05:38
  • 1
    @Robert: "other languages", plural, no mention of any specific language other than C. How do you possibly read "Java" from that? – Robert Gamble Jan 07 '09 at 05:46
  • @Roberd: Several of the answers that had been posted before I encountered the question were talking about Java (or other languages whose implementation is often via interpreter or VM). – joel.neely Jan 07 '09 at 13:42
  • 4
    @Joel - If you know your target hardware, most optimizations the JVM can do at runtime can also be done by using profile-guided optimization with C or C++. That makes a *huge* difference, and generally pushes C and C++ back in the lead, since they don't have to "learn" while executing. – Tom Jan 14 '09 at 05:25
  • 1
    The biggest problem with the virtual machines, in my opinion, is that they do all of this dynamic tuning and compiling, but forget all of it at program exit. This is why C programs like `ls` start and finish in microseconds while a Java `ls` would probably take half a second to run. – Zan Lynx May 11 '11 at 20:12
  • ...and 2 years on and the theoretical advantages of dynamic profiling still haven't materialized: java/.NET still tend to be much slower at cpu-bound computation. The extra runtime info in *theory* allows more complex and smarter optimizers; but it's clear from benchmarks that the actual optimizers are in fact much more rudimentary. Based on my own anecdotal evidence: if anything; C++ has gained ground, not lost it, over the last few years. (I nevertheless do most coding in managed languages - I'm not saying this because I love C or C++ very much). – Eamon Nerbonne Feb 04 '13 at 14:44
  • You forget that the VM abstraction is only part of the story why Java is slow. The other parts are: Slow array accesses due to bounds checks, slow function calls due to all-virtual methods (can be mitigated with `final`), and slow variable creation due to all-heap objects. You simply cannot beat taking the address of an `int` on the stack to pass it to a function by first allocating some memory, then constructing an `Integer` object in it, forgetting about the pointer, and finally using garbage collection to determine that you can actually reuse the memory. – cmaster - reinstate monica Feb 24 '20 at 16:50
4

The fastest running code would be carefully handcrafted machine code. Assembler will be almost as good. Both are very low level and it takes a lot of writing code to do things. C is a little above assembler. You still have the ability to control things at a very low level in the actual machine, but there is enough abstraction, make writing it faster and easier then assembler.

Other languages, such as C# and Java, are even more abstract. While Assembler and machine code are called low-level languages, C# and JAVA (and many others) are called high-level languages. C is sometimes called a midlevel language.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jim C
  • 4,981
  • 21
  • 25
  • While reading your answer, just two words in the whole paragraph were pulling my eyes towards them, like a magnet pulling metals. The word is JAVA, twice in the paragraph. Never seen it before written in all caps, and it's looking good :-) – Sнаđошƒаӽ Dec 02 '16 at 04:50
3

Don't take someone’s word for it; look at the disassembly for both C and your language-of-choice in any performance critical part of your code. I think you can just look in the disassembly window at runtime in Visual Studio to see disassembled .NET code. It should be possible, if tricky, for Java using WinDbg, though if you do it with .NET, many of the issues would be the same.

I don't like to write in C if I don't need to, but I think many of the claims made in these answers that tout the speed of languages other than C can be put aside by simply disassembling the same routine in C and in your higher level language of choice, especially if lots of data is involved as is common in performance critical applications. Fortran may be an exception in its area of expertise; I don't know. Is it higher level than C?

The first time I did compare JITed code with native code resolved any and all questions whether .NET code could run comparably to C code. The extra level of abstraction and all the safety checks come with a significant cost. The same costs would probably apply to Java, but don't take my word for it; try it on something where performance is critical. (Does anyone know enough about JITed Java to locate a compiled procedure in memory? It should certainly be possible.)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
3

Setting aside advanced optimization techniques such as hot-spot optimization, pre-compiled meta-algorithms, and various forms of parallelism, the fundamental speed of a language correlates strongly with the implicit behind-the-scenes complexity required to support the operations that would commonly be specified within inner loops.

Perhaps the most obvious is validity checking on indirect memory references—such as checking pointers for null and checking indexes against array boundaries. Most high-level languages perform these checks implicitly, but C does not. However, this is not necessarily a fundamental limitation of these other languages—a sufficiently clever compiler may be capable of removing these checks from the inner loops of an algorithm through some form of loop-invariant code motion.

The more fundamental advantage of C (and to a similar extent the closely related C++) is a heavy reliance on stack-based memory allocation, which is inherently fast for allocation, deallocation, and access. In C (and C++) the primary call stack can be used for allocation of primitives, arrays, and aggregates (struct/class).

While C does offer the capability to dynamically allocate memory of arbitrary size and lifetime (using the so called 'heap'), doing so is avoided by default (the stack is used instead).

Tantalizingly, it is sometimes possible to replicate the C memory allocation strategy within the runtime environments of other programming languages. This has been demonstrated by asm.js, which allows code written in C or C++ to be translated into a subset of JavaScript and run safely in a web browser environment—with near-native speed.


As somewhat of an aside, another area where C and C++ outshine most other languages for speed is the ability to seamlessly integrate with native machine instruction sets. A notable example of this is the (compiler and platform dependent) availability of SIMD intrinsics which support the construction of custom algorithms that take advantage of the now nearly ubiquitous parallel processing hardware—while still utilizing the data allocation abstractions provided by the language (lower-level register allocation is managed by the compiler).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • 1
    Some of this memory allocation advantage of C can probably also be replicated in other languages by clever compilers (see [here](https://stackoverflow.com/a/10618981/86967)). I get the impression, though, that this is somehow structurally very difficult to do -- especially for non-primitive data types. [This post](https://stackoverflow.com/a/6604390/86967) mentions the idea of a *non-escaping object* which can be stack-allocated as an optimization in Java. – Brent Bradburn Dec 18 '17 at 16:28
2

1) As others have said, C does less for you. No initializing variables, no array bounds checking, no memory management, etc. Those features in other languages cost memory and CPU cycles that C doesn't spend.

2) Answers saying that C is less abstracted and therefore faster are only half correct I think. Technically speaking, if you had a "sufficiently advanced compiler" for language X, then language X could approach or equal the speed of C. The difference with C is that since it maps so obviously (if you've taken an architecture course) and directly to assembly language that even a naive compiler can do a decent job. For something like Python, you need a very advanced compiler to predict the probable types of objects and generate machine code on the fly -- C's semantics are simple enough that a simple compiler can do well.

Joseph Garvin
  • 20,727
  • 18
  • 94
  • 165
2

Back in the good ole days, there were just two types of languages: compiled and interpreted.

Compiled languages utilized a "compiler" to read the language syntax and convert it into identical assembly language code, which could than just directly on the CPU. Interpreted languages used a couple of different schemes, but essentially the language syntax was converted into an intermediate form, and then run in a "interpreter", an environment for executing the code.

Thus, in a sense, there was another "layer" -- the interpreter -- between the code and the machine. And, as always the case in a computer, more means more resources get used. Interpreters were slower, because they had to perform more operations.

More recently, we've seen more hybrid languages like Java, that employ both a compiler and an interpreter to make them work. It's complicated, but a JVM is faster, more sophisticated and way more optimized than the old interpreters, so it stands a much better change of performing (over time) closer to just straight compiled code. Of course, the newer compilers also have more fancy optimizing tricks so they tend to generate way better code than they used to as well. But most optimizations, most often (although not always) make some type of trade-off such that they are not always faster in all circumstances. Like everything else, nothing comes for free, so the optimizers must get their boast from somewhere (although often times it using compile-time CPU to save runtime CPU).

Getting back to C, it is a simple language, that can be compiled into fairly optimized assembly and then run directly on the target machine. In C, if you increment an integer, it's more than likely that it is only one assembler step in the CPU, in Java however, it could end up being a lot more than that (and could include a bit of garbage collection as well :-) C offers you an abstraction that is way closer to the machine (assembler is the closest), but you end up having to do way more work to get it going and it is not as protected, easy to use or error friendly. Most other languages give you a higher abstraction and take care of more of the underlying details for you, but in exchange for their advanced functionality they require more resources to run. As you generalize some solutions, you have to handle a broader range of computing, which often requires more resources.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul W Homer
  • 2,728
  • 1
  • 19
  • 25
  • "In C, if you increment an integer, it's more than likely that it is only one assembler step in the CPU" Not exactly true. If this integer is not in the CPU register, then you need to have the machine code to fetch it from memory, increment it, write it back into memory. About the same one would expect to happen when running Java code. And I don't get the idea why "++i" would trigger by itself a GC cycle. – quant_dev Jun 22 '09 at 21:08
  • @quant_dev: "you .. have ... to fetch it from memory, increment it, write it back...". Maybe, maybe not. The x86, for instance, has instructions that operate on data in memory. `++i` might compile to "add [ebp - 8], 1". Not to say that fetch, increment, store isn't still happening, but this is taken care of by the CPU, and is just one instruction, as Paul said. – P Daddy Jun 22 '09 at 21:27
  • ... which is still irrelevant from the POV of the performance, because it might be just one instruction, but still involve waiting for the data to arrive to CPU. Cache misses and all that. – quant_dev Jun 22 '09 at 21:36
  • No, I wouldn't say it's irrelevant. One CPU instruction usually occupies fewer code bytes than multiple CPU instructions, yielding better cache performance on the code segment. One CPU instruction also takes up less room on the CPU's pipeline, and the multiple steps (fetch, increment, store) can be handled—perhaps in parallel—by the separate pipeline stages. In fact, some parts of an operation may even be skipped if they can be melded with other operations on the pipeline. For instance, storing a value can be melded with a subsequent loading of the same value. – P Daddy Jun 22 '09 at 22:20
1

Some C++ algorithms are faster than C, and some implementations of algorithms or design patterns in other languages can be faster than C.

When people say that C is fast, and then move on to talking about some other language, they are generally using C's performance as a benchmark.

Arafangion
  • 11,517
  • 1
  • 40
  • 72
  • 2
    "Some C++ algorithms are faster than C" does not make sense. Any "C++ algorithm" can be written in C and vice versa. Algorithms are language agnostic. C++ essentially adds features to C -- and none of these new features lead to faster algorithms (though they maybe easier to write). – Joseph Garvin Jan 14 '09 at 03:28
  • 2
    The classic rebuke is std::sort algorithm.. std::sort is faster than any sort algorithm in C - the only way to get the same performance in C is to hard-code it everywhere you want or use macros - and even then the compiler has less information to optimize. – Arafangion Feb 13 '09 at 05:20
1

With modern optimizing compilers, it's highly unlikely that a pure C program is going to be all that much faster than compiled .NET code, if at all. With the productivity enhancement that frameworks like .NET provide the developer, you can do things in a day that used to take weeks or months in regular C. Coupled with the cheap cost of hardware compared to a developer's salary, it's just way cheaper to write the stuff in a high-level language and throw hardware at any slowness.

The reason Jeff and Joel talk about C being the "real programmer" language is because there isn't any hand-holding in C. You must allocate your own memory, deallocate that memory, do your own bounds-checking, etc. There isn't any such thing as new object(); There isn't any garbage collection, classes, OOP, entity frameworks, LINQ, properties, attributes, fields, or anything like that.

You have to know things like pointer arithmetic and how to dereference a pointer. And, for that matter, know and understand what a pointer is. You have to know what a stack frame is and what the instruction pointer is. You have to know the memory model of the CPU architecture you're working on. There is a lot of implicit understanding of the architecture of a microcomputer (usually the microcomputer you're working on) when programming in C that simply is not present nor necessary when programming in something like C# or Java. All of that information has been off-loaded to the compiler (or VM) programmer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Robert C. Barth
  • 22,687
  • 6
  • 45
  • 52
  • "Thow more hardware at the problem" only works in environments where that's actually possible. The embedded market is a perfect counter-example (and that is a *massive* market). – Bob Somers Jan 07 '09 at 05:47
  • Jeff and Joel blog solely about business systems, not embedded systems, so it's reasonable to assume that that is the context in which this question was asked. – Robert C. Barth Jan 07 '09 at 06:07
  • 1) .net code running as fast as C code? Have you ever actually written a C program? 2) The "throw more hardware at the problem" mentality is why my 1.3GHz dual core 2GB machine can barely keep up with Windows XP while my 800MHz 512MB machine flys with the latest version of Ubuntu. – Robert Gamble Jan 07 '09 at 06:09
  • Yes, I've written C. It's not as glorious as people make it out to be. And projects cost too much. It's a simple case of economics. I ran Win2k on a Pentium Pro 180MHz with 768MB RAM for years as a mail and web server. It ran just fine. Anecdotal evidence means nothing. – Robert C. Barth Jan 07 '09 at 06:18
  • C isn't "glorious" but it is fast, I have written enough C and C# code to know that C almost always much faster than C# while performing the same task. For some tasks it takes longer to develop in than higher-level languages but it's all about using the right tool for the job and sometimes C is it. – Robert Gamble Jan 07 '09 at 06:27
  • Anecdotal evidence aside, the point is that the "hardware solving slowness" mentality is the cause of a lot of unnecessary software bloat. – Robert Gamble Jan 07 '09 at 06:29
  • Your reasoning makes sense for most internal business applications, but there is a whole world of software out of that domain to which it does not apply. There is no way my employer could buy "cheap hardware" to every single user of our software. – Nemanja Trifunovic Jan 08 '09 at 21:09
  • I'm offsetting one of your down-votes because I think you know what you're talking about, although, as I sometimes do, you came down a little heavy on one side of the argument. – Mike Dunlavey Jan 08 '09 at 21:10
  • Compiled .NET code is still garbage collected. It's also likely to do a ton of run time checks on things like array bounds that C wouldn't. Although you're write about the productivity boost, strictly speaking I don't think your answer is right for CPU bound applications. – Joseph Garvin Jan 14 '09 at 03:12
  • Well-optimized C code with profile-guided code generation will be much faster than equivalently-optimized .NET code. It takes much longer to develop, sure, but don't just write off the very real performance impact. – Tom Jan 14 '09 at 05:30
  • I remember Mircrosoft announcing they were code the next windows in .net. Did that happen? – Jasen Jan 11 '17 at 21:09
1

Just step through the machine code in your IDE, and you'll see why it's faster (if it's faster). It leaves out a lot of hand-holding. Chances are your Cxx can also be told to leave it out too, in which case it should be about the same.

Compiler optimizations are overrated, as are almost all perceptions about language speed.

Optimization of generated code only makes a difference in hotspot code, that is, tight algorithms devoid of function calls (explicit or implicit). Anywhere else, it achieves very little.

Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135
1

It's the difference between automatic and manual. Higher-level languages are abstractions, thus automated. C/C++ are manually controlled and handled; even error checking code is sometimes a manual labor.

C and C++ are also compiled languages which means none of that run-everywhere business. These languages have to be fine-tuned for the hardware you work with, thus adding an extra layer of gotcha. Though this is slightly phasing out now as C/C++ compilers are becoming more common across all platforms. You can do cross compilations between platforms. It's still not a run everywhere situation, and you’re basically instructing compiler A to compile against compiler B the same code on a different architecture.

Bottom line, C languages are not meant to be easy to understand or reason. This is also why they’re referred to as systems languages. They came out before all this high-level abstraction nonsense. This is also why they are not used for front end web programming. They’re just not suited to the task; they’re meant to solve complex problems that can't be resolved with conventional language tooling.

This is why you get crazy stuff, like micro-architectures, drivers, quantum physics, AAA games, and operating systems. There are things C and C++ are just well suited for. Speed and number crunching being the chief areas.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Val
  • 11
  • 1
1

C is fast because it is natively compiled, low-level language. But C is not the fastest. The Recursive Fibonacci Benchmark shows that Rust, Crystal, and Nim can be faster.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bill Zelenko
  • 2,606
  • 1
  • 17
  • 26
1

There are many reasons, including:

  • It compiles into assembly language.
  • It is statically typed.
  • No garbage collection.
  • No exception mechanism.
  • Compiler optimizations
  • Part of the philosophy of C is to keep things simple and maintain backwards compatibility, instead of adding more features.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sapphire_Brick
  • 1,560
  • 12
  • 26
  • Why should it be faster because it is not object-orionted? – sb27 Feb 23 '20 at 21:13
  • A) object oriented programming creates a need for garbage collection, B) big features like object oriented programming add complexity to the compiler, – Sapphire_Brick Feb 24 '20 at 15:42
  • 1
    A) Nope. See C++ or Rust. B) Yes, but it also gives the Compiler opportunities for new optimizations. – sb27 Feb 24 '20 at 17:09
  • A) Rust has compile-time garbage collection, and c++ has garbage collection for classes, that's why it has destructors,, B) optimized complexity is still complexity – Sapphire_Brick Feb 25 '20 at 15:54
  • 1
    A) It's not garbage-collection, memory management has to be done even if you make your program in assembly B) Nope. More Abstraction allows the optimizer to make better assumptions. – sb27 Feb 25 '20 at 19:48
  • I'm not going to keep arguing with you, but i'll edit it if you insist. – Sapphire_Brick Feb 25 '20 at 20:14
  • Nice, that is what I wanted to achieve ;D – sb27 Feb 27 '20 at 19:10
0

Actually, in certain applications (numerics) even C can be beaten, and I don't mean assembly language, but the old, oft-ridiculed Fortran. The reason is, Fortran guarantees no pointer aliasing.

quant_dev
  • 6,181
  • 1
  • 34
  • 57
  • 1
    My compiler has the option "allow pointer aliasing only across functions" for a reason. – Joshua Oct 26 '10 at 19:01
  • 1
    Compiler trying to avoid something is different than the language guaranteeing the absence of it. – quant_dev Nov 10 '10 at 03:22
  • Of course you could always use the restrict keyword in C. Problem solved. – cdcdcd Apr 17 '16 at 21:05
  • 1
    Not really. C compiler is not required to honor it, AFAIK. – quant_dev Apr 19 '16 at 06:28
  • 1
    Not to mention Fortran compilers and runtimes were generally much more performance-optimised than C ones: when your code is simulating atomic weapons on the fastest machine you can make then you probably have a lot of money to throw at very good compilers. –  Aug 30 '16 at 22:02
0

Even the difference between C and C++ can at times be great.

When you are allocating memory for an object, invoking constructors, aligning memory on word boundaries, etc. the program winds up going through a lot of overhead that is abstracted away from the programmer.

C forces you to take a look at each thing that your program is doing, generally at a very fine level of detail. This makes it harder (although not by any means impossible) to write code that does a lot of tasks that are unnecessary to the immediate goal at hand.

So where in, for instance a BASIC program you would use the INPUT keyword to read a string form STDIN and automatically allocate memory for its variable, in C the programmer will typically have already allocated memory and can control things like whether the program blocks for I/O or not, and if it stops reading input after it has the information it needs or continues reading characters to the end of the line.

C also performs a lot less error-checking than other languages, presuming the programmer knows what they're doing. So whereas in PHP if you declare a string $myStr = getInput(); and go on to reference $myStr[20], but the input was only 10 characters long, PHP will catch this and safely return to you a blank string. C assumes that you've either allocated enough memory to hold data past the end of the string or that you know what information comes after the string and are trying to reference that instead. These small factors have a huge impact on overhead in aggregate.

Max
  • 1,044
  • 10
  • 19
  • On the other hand, both template-based inlining in C++ and more frequent stack-based allocation can make big differences as well. Though they do come with their own costs as well. – Tom Jan 14 '09 at 05:32
  • What PHP does is anything but safe. In some instances, it's actually WORSE than C's behavior. In C you have a decent chance of causing a crash when you try to write to out of bounds memory. In PHP your code will continue going along silently, unless you're lucky enough that the returned empty string triggers a more visible bug. A language should complain somehow when you access an array out of bounds, unless you go out of your way to specify that you're using a special type of array that creates empty members on demand. Intentional is good. – Joseph Garvin Aug 08 '09 at 19:57
  • @Joseph: That crash just might be a security exploit instead. – Joshua Oct 26 '10 at 19:00
  • @Joshua: The PHP behavior is just as likely to be a security exploit (e.g. you forget to check if a dictionary has a user in it before accessing it, now by accessing it you put the user in the dictionary which gives them access to other parts of the system). At least the C behavior has a chance of 'notifying' you ;p – Joseph Garvin Oct 26 '10 at 19:05
0

It's all about time and effort.

Given an infinite amount of time and effort:

  • An assembly program will be faster than one written in C.
  • A C program will be faster than one written in C++.

Given an fixed amount of time and effort:

  • A C++ program will be faster than one written in C.
  • A C program will be faster than one written in Assembly.

Why? Because the more abstraction you do, the more time you can spend optimising the critical sections of code that really matter. A couple of assumptions here is a developer is equally competent in all three languages, you don't care about binary size, memory usage, etc.

Every abstraction has a cost performance-wise but should make code easier and faster to write.

ericcurtin
  • 1,499
  • 17
  • 20
  • A C++ program will be faster than one written in C. Yeah, no. Maybe if only using the so called "C" subset, but if you are good C++ drone with RAII and magic pointers bullshit, you will get slower than regular C. And if you only use "C" subset, then is really c++ that is faster? – Enerccio Jul 28 '18 at 22:03
  • Did you fully read my answer? Given an infinite amout of time an effore, a C program will be faster than one written in C++. Who said you have to user RAII and magic pointers bullshit? That's optional. Even the simple things such as vectors and C++ strings can drastically speed up development time. – ericcurtin Jul 30 '18 at 17:48
  • Actually they might "speed" the development part, but they will certainly slower translation part and debugging part and maintenance part. Seriously C++ is bad mess of a language. – Enerccio Jul 30 '18 at 20:26
  • I've never heard anyone that's had serious problems debugging and maintaining vectors and C++ strings – ericcurtin Jul 31 '18 at 13:13
  • Re *"A C++ program will be faster"*: Faster to run or faster to write? Can you make it clearer in your answer? (But **** ***without*** **** "Edit:", "Update:", or similar - the answer should appear as if it was written today) – Peter Mortensen Feb 11 '23 at 18:07