tags:

views:

3472

answers:

26

In listening to the StackOverflow 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?

+6  A: 

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 langs are oriented more on programmer productivity rather than performance. Hardware is cheap now days. Also compilation to intermediate representation gives a lot of bonuses such as security, portability etc. .NET CLR can take advantage of different hardware - for example you don't need to manually optimize/recompile program to use SSE instructions set.

aku
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
@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
@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
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
@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
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
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
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
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
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
for portable gui what be your choice ? Main will be QT :)
Ilya
WinForms (Windows, *NIX, MacOS) :) Unfortunately can't be used in some mobile OS
aku
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
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
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
+29  A: 

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.

JosephStyons
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
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
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
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
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
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
@Max: I've read your comment 3 times and I still don't understand it.
Robert Gamble
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
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.
Arkadiy
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
+3  A: 

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
+2  A: 

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
+19  A: 

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 2 levels of abstraction away from machine language. Java and the .Net languages are at a minimum 3 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.

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

Rob Allen
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
.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
@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
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
@Adam: What instructions are you thinking of? (asking not challenging, I'm unfamiliar)
Joseph Garvin
Maybe ThumbEEhttp://en.wikipedia.org/wiki/ARM_architecture#Thumb_Execution_Environment_.28ThumbEE.29
Roman A. Taycher
+21  A: 

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 bound
  • 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.

Johannes Schaub - litb
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?
Parvenu74
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
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
@Pax -- Nice one :)
zenazn
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
@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
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
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
This should be the accepted answer in my opinion.
Brian R. Bondy
@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
A: 

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
"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
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
+61  A: 

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 Vitual 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.

coobird
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.
porneL
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
There's nothing preventing a C program from performing the same chunked allocation and garbage collection, aside from being "hard".
ephemient
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
+4  A: 

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 layor of abstraction. The lack of object oriented features as a part of the language also increases it's 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, inharitence, etc. This means rather then make something generalized enough for everyone with the amount of code and the performance penelty that requires you only write what you need to get the job done.

Jared
+5  A: 

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
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 Robinson
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
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
@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
+4  A: 

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
+11  A: 

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 Great Language Shootout 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.

Norman Ramsey
It's possible to write non-obviously expensive code in any language. It's just that in some languages, you have to write an inner variant of Lisp or Forth first…
Donal Fellows
+5  A: 

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
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
Java is an "other language" referenced by the OP, is it not?
Robert C. Barth
@Robert: "other languages", plural, no mention of any specific language other than C. How do you possibly read "Java" from that?
Robert Gamble
@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
@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
+3  A: 

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 IO, 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 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.

James
"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
@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
@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
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
+9  A: 

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 aliassing 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 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.

You get the drift ?

Any our good friend, the x86, executes an instruction set that these days bears little relationship to the actual CPU archientecture. 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 there C isn't close to the metal, but it is close to the compiler. Which will do whole program optimization. Weird.

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

Tim Williscroft
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
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
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
A: 

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
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
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
@Joseph: That crash just might be a security exploit instead.
Joshua
@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
+1  A: 

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 is no hand-holding in C. You must allocate your own memory, deallocate that memory, do your own bounds-checking, etc. There's no such thing as new object(); There's no 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.

Robert C. Barth
"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
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
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
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
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
Anecdotal evidence aside, the point is that the "hardware solving slowness" mentality is the cause of a lot of unnecessary software bloat.
Robert Gamble
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
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
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
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
+5  A: 

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
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
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
@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
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
+3  A: 

The fastest running code would be carefully hand crafted 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 middle level language.

Jim C
A: 

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
+1  A: 

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

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

Daemin
+1  A: 

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
+1  A: 

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.

Paul.

Paul W Homer
"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
@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
... 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
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
I stand corrected.
quant_dev
A: 

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
My compiler has the option "allow pointer aliasing only across functions" for a reason.
Joshua
+1  A: 

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
That is an API issue, not a language issue.
Arafangion
@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
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
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
A: 

Don't take someones word for it, look at the dissassembly 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. 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, don't know. Is it higher level than C?

First time I did compared 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. Same costs would probably apply to Java, but don't take my word for it, try it on something where performance is critical. (Anyone know enough about JITed Java to locate a compiled procedure in memory? It should certainly be possible)

John Robertson