Shlomi Fish has written a new essay titled “When C is the Best? (Tool for the Job)”. Its theme is giving several reasons (besides high speed and low memory consumption) why some code should still be written in C.
Shlomi Fish has written a new essay titled “When C is the Best? (Tool for the Job)”. Its theme is giving several reasons (besides high speed and low memory consumption) why some code should still be written in C.
I had to suffer through a 100+-email, week-long battle between C and Fortran on the Computational Chemistry List, and yet this guy doesn’t even mention it?
So, Fortran 95 rules! Go usable arrays and libraries of good numerical routines! C sucks.
There we go.
Its pretty obvious that for low-leveled stuff, integrability, and speed/memory consumption, C is best. All the other reasons are almost specific to Java (and/or mono/.net). So basicly he is reiterating the first well known reasons.
Then he comes and brings an example from his own program and why he would be uncomfterble using anything else. Then he goes and assumes how in every other no-C language it would be slower without even proving his claims. I actualy think that it would of been interesting to see an actual comparison between his C program and another implmentation in some compileable functional language. Well, that is if he would of actually DONE some comparison.
Last, who the heck ever argued with this article? Infact, afaik, in the python community it is a well accepted paradigm to write some time critical code in C and then add it as a module to the rest of your program. Heck there have been quite a few commercial games that had thier game engine written in C and everything else written in python (like implementation of the different units, map scripting, etc…)
What games out of curiosity?
I’ve noticed a lot more coverage of Python lately. Pretty cool.
if I remember correctly, E.V.E. used Python, I might be wrong though.
All the time, we hear repeated that C is portable. This is a misnomer. It gives the wrong impression that identical code will work in the identical way on different architectures. It’s not the PROGRAM that is portable, it’s the LANGUAGE. It was abstracted so that programs could be written using the same language constructs on different machines; so that you as a programmer could immediately get familiar with another environment on another system; because the compiler was easy to port. But not that the compiler, or your program would give identical results.
This to my mind is one of C’s greatest weaknesses – this illusion of portability.
There is a reason for C’s longevity. But it’s more due to the innate conservativeness of the internal computing world, which is paradoxical given the radical changes IT has brought to the external world, than any inherent strengths in C itself.
Geoff Gigg
C code should function the same on different architectures if you mind your types…
It’s only when you get into things that aren’t really within c’s logic you get into trouble: Using ints as pointers, using shift operators, and writing asm sections.
As long as you are on a “c machine” and since Lisp machines seem to have dissappeared (physically speaking), I think you can be pretty sure you’ll be on a “c machine.”
Developers are conservative because they don’t like menial tasks like porting that c code to the latest fad language. It’s not perfection you need in a language, it’s having it still be there in 10 years that you need. (Not to mention all the other important stuff, like not sucking so bad you can’t do anything in it).
I’d say that code written in a portable language is portable…. It sort of “inherits” its portability from the portability of the compiler/runtime/machine. The trouble is that a lot of c code is written with a specific machine in mind, and that machine wasn’t the c machine it was say Intel x86. So they did nice things like assuming sizeof *int == sizeof *(char *). Or assuming that int x = 1; x = x >> 48 would equal x >> 16.
As long as you are on a “c machine” and since Lisp machines seem to have dissappeared (physically speaking), I think you can be pretty sure you’ll be on a “c machine.”
Good Lisp implementations have existed for both Lisp machines and C machines. Good C implementations have never existed for a Lisp machine. What does that say about C’s vaunted portability? You’re basically saying: C is portable as long as you only try to port it to machines designed for C. Duh. Does that mean it is portable, or does that merely mean that it’s so popular that most machines are designed for it?
If I was slightly unclear: the reason a good C implementation never existed for a Lisp machine was because the LispM couldn’t emulate C’s lack of type and memory safety. A good Java or Perl implementation would have been entirely possible on a LispM.
> This to my mind is one of C’s greatest weaknesses – this illusion of portability.
Illusion ? It is the most portable language (of course, by portability we mean source code portability).
Illusion ? It is the most portable language (of course, by portability we mean source code portability).
It’s portable as long as your program only does portable things, like text processing and math.
However, C is a portability nightmare when it comes to things like networking, graphics, and several other things. Additionally, people talk about C like there’s only one version of it. There are in fact several, the most popular of which are K&R, ANSI C 89, ANSI C 99, and GNU C. Yes, GNU C does add its own extensions, and yes programmers do use them. (It is possible to have vendor lock-in in open source, it just isn’t as big of a problem when it happens.)
C is also unportable during the act of compiling and linking. There are several different C compilers that use different command line options. Commonly used C libraries can be placed in any number of locations and given any number of names on people’s computers. That’s why we have the mess that is the GNU autotools.
You must see how Plan9 has archieved the higher portability grade with C.
And you can see why the creators choose to back to C instead of the original language used.
“Most portable language”?!? You know how easy it is to get endianess wrong or to use non-portable libraries in C (yes that’s source compatibility even)? Now compare that to java or c#, or look at all the apps for ms-windows that can’t/won’t be ported to linux/unix and then look at all the java apps that run out of the box on linux, macos/x and windows.
Code portability with C means to the same compiler on a different platform. C Compiler compatibility is a different matter. Each compiler seems to have its own features and quirks which can cause the same C code to behave differently depending on which compiler it was compiled with (assuming it will compile the foreign code at all). And then of course there are platform dependencies in the actual code which are hard to avoid because nothing shields you from the system specific hardware and system specific libraries except programmer discipline.
Java has the advantage of a well specified language (unlike C), well specified run-time environment (unlike C) and well specified APIs (unlike C). The behavior of Java programs on different implementations of the run-time engine and compiled with different versions of the compiler against different implementations of APIs is well defined: anything deviating from the spec may be considered a bug. So you can can compile with the ibm compiler on AIX and test on webshpere, run on the sun jvm on solaris and jboss or use Jrockit to run it on win32 with bea weblogic. If any of this requires code changes you have encountered a bug in either the compiler, run-time environment or the API implementation. The before mentioned application servers are known to have interoperability issues due to different implementations of the huge amount of APIs they support.
Hopefully you’ll understand that source portability is probably pretty damn close to perfect. Most of the portability problems of java programs from one platform to another are caused by api portability problems. For example the oracle implementation of the servlet API is on paper equivalent to the apache tomcat implentation. Indeed many applications that use this API run fine on both, but not all. The reason is that oracle did nog quite get all the semantic details right in their implementation. If you depend on the correct behavior of some of these things, you will encounter problems.
The problem isn’t any different if you compare the SUN linux jvm and the win32 jvm. Indeed most of the java code of the library is identical for both platforms (no problems there). The native code it depends on however is not. A considerable part of the java API has been designed to cover up for native code portability issues (graphics, io, processes & threads). Sometimes it fails to do that properly and that’s when you encounter problems porting java applications from win32 to linux or vice versa.
“C is a disease, and it’s spreading”
I read that line many many years ago, I believe on BYTE magazine.
C is still spreading, and yes, it’s a disease!
I programmed in C for 15+ years, and when I found Python, I will never look back at C again!
C is good for intermediate target language, because of the availability of many ANSI C compilers. So what we’ll see in the following years, is many high level languages creating C/C++ code to create final executables.
So basically C will move down a layer.
I’ve never seen the point of C when compared to Pascal. It seems needlessly complex to me (pointers to arrays of chars instead of strings ? why oh why !)
An array of chars _is_ a string
All languages are similar.
According to Tiobe, which has reasonable metrics (for what can be an unreasonable, difficult to measure, clannish subject), C is currently number 2 in programming language popularity. This after leading recently until Java 5.0 came out, which propelled Java back to the number one spot.
So why is C still in such widespread use? C has a lot of detractors, yet it’s still being used massively to build real world systems and solve real world problems. In spite of some of the difficulities with C programming (it’s mid level, almost lower level, and requires handling bits, pointers and direct memory management), C is still a very effective tool.
Personally, I’m very glad that C remains in widespread use. I hate bloated, slow, memory consuming software, and “managed” languages, like Java and .Net, seem to invite the programmer to make their code as slow and bloated as possible, plus the huge overhead of the virtual machine and garbage collector. Yes, memory is relatively cheap, and yes, CPUs, even cheap ones, are quite fast these days. But when you start using resource hungry programs, it all adds up real quick.
So, Viva C!
That’s not a misfeature. In the hardware, strings ARE arrays of chars. A string is an abstraction and C doesn’t hide that from you.
Most modern pascal compilers let you use a string also as an array of chars. While it’s true that string is an abstraction, the notion of string exists even on hardware implementations – check scas* opcodes on x86. (And yes, I’m aware those aren’t string-specific, on the sense of char array)
The lack of abstraction is C’s problem. You are being tricked into thinking your program is portable when it isn’t. Just because you can compile your C program on any platform doesn’t mean it’ll do the same on every platform:
C doesn’t abstract endianess. It doesn’t abstract a platform’s native memory alignment or pointer size. Strings as null-terminated byte arrays don’t work with 16bit Unicode (which you should expect that one or the other function on a target platform may actually return – like a file name).
From the article:
“ANSI C is portable for every architecture there’s a gcc backend or any other compiler for.”
ANSI C shouldn’t have to rely on GCC for portability, that’s kind of the point of it being ANSI C in the first place. Later, he laments about the aspects that he cannot use when trying to run cross platform compiling against Visual C++ etc.
“With Java you rely on Sun’s whims.”
With Java, you have to rely on Suns Java Compatability Kit and testing. There are several JVMs that appear to meet this standard, otherwise they could not be called “Java”. Not just Sun, but IBM, BEA, HP, Apple, as well as several Java implementations on embedded devices. I acknowledge that there are other platform and higher level issues with portability at the embedded layer that are not part of the the Java language and JVM itself per se.
“Open-source high level languages are better (especially if they can be compiled using gcc or supply a gcc back-end), but nonetheless, C is still more portable than anything written using it.”
Since these are simply C programs, their portability is manifest to the ability of the coders to create portable code. They are no more or no less portable than other C programs that leverage similar facilities exposed by the operating system.
“gcc is a full-featured and robust compiler for ANSI C, and it’s open-source. Sun’s Java distribution has a very problematic license. It’s not distributed as part of most Linux distributions due to this.”
License has nothing to do with portability. I imagine, but do not know, that Auto Lisp in AutoCAD is quite portable, for a contrived example.
“You cannot effectively duplicate a struct containing other structs in Java or in Perl as you can in C. This is due to the fact that in these languages every struct is a reference. You cannot work with interrupts, DMAs, and other hardware elements. It’s much harder to write your own custom fine-grained memory-management routines.”
Hmm, a quick google seems to conflict with those claims, as there seems to be at least some folks doing real time embedded Java.
“Many problem domains call for ANSI C.”
True, but those domains are getting fewer and fewer.
“You can compile a C library and distribute it as is. With Java or Perl one often needs a substantial run-time.”
I can compile a Java library and distribute that alone to anyone who has the Java runtime. There are a gazillion of the libraries available on the internet. Arguably, I’d say there are more (at least in terms of variety and number) of these than for C, particularly higher level frameworks and development runtimes (I don’t know if there is an equivalent C Library to something like, say, Spring for example). In fact, it can be argued that simply the simplicity of distributing and incorporating 3rd party libraries is what has lead to the rapid rise and use of Java in the first place.
Finally, that Java library binary is portable to the PC, Mac, Solaris, AIX, HPUX, Linux, FreeBSD, AS/400, PowerPC, i386, ARM, etc. Whereas a C library binary typically is not.
“There’s no fork() in Java, and not many other UNIX system calls. You need to create bindings for them (which require JNI) or work around them. Perl and other languages, usually don’t have this limitation.
To some extent, this is also true when working on Microsoft Windows, where some of the system calls and APIs are not available in the Java distribution by Sun.”
That’s ok, C has to jump through a lot of hoops to leverage the JVM, so, what’s your point? UNIX programs have to jump through there own circles of Hell to run on Windows, and it’s even worse running Windows programs on UNIX. What’s this have to do with C as a language?
“A C library can be used by Perl code, Python code, Tcl code, Ruby code, to a lesser extent Java code, etc. Code written in a high-level language is mostly usable only in that language.”
Ah HA! The crux of the issue. I see here you don’t consider C a high level language.
“And naturally there’s speed and memory consumption. Often when speed or low memory consumption is the issue, one cannot use a high-level language, because it may have a lot of overhead in both areas or both. Many real-time applications (i.e: applications that should respond to events within a given time) must be written in a low-level language for that reason.”
Umm…no, Real Time Applications must not necessarily be written in a low level language. Real Time has to do with guaranteed dispatch and response, much of which is dependant on the runtime. It all depends on the environment, how fast your processor is, and how much you’re doing in your real time event handlers. Lots of applications that need real time response can be handled with all sorts of runtimes. There are and have been real time systems written in Lisp, for example, and folks are doing that in Java today.
“Other applications like that are applications that simply can never be fast enough: various APIs, virtual machines, simulations, graphics, audio, video and 3-D programs, etc.”
And of the billions of lines of code written each year by developers around the world, less and less and less of it is in that low level space, most of it is in integrating those low level aspects into high level applications. Even modern video games are more and more runtime engines driven and integrated by scripting languages.
Back in the day, we’d write assembly interrupt handlers to be leveraged by C code. Once we could do that, assembly dropped from mainstream to a very nichey area of development. C is suffering the same fate. Now we’re writing C handlers for Java/Python/Ruby code, and most of the folks writing in those languages are not looking back. The domain they develop in rarely need the pain of writing C code to perform the task they need.
Certainly there are exceptions, and certainly C has its place in the world, but that place is getting smaller and smaller every day.
I don’t doubt that if he ported his freecell solver to java, the c version would still be faster. But he doesn’t seem to be very knowledgeable about java in general. He just likes to ring off things and say that they’re automatically slower, just because they’re java.
Functions? Must be slower! For loops? Must be slower!.. I don’t think he realizes what a JIT compiler can do. A final method is easy for a compiler to inline, which would make it roughly equivalent to a macro. And if you’re porting directly from c, it’s obviously very easy to make many of your methods final.
You can’t compile and distribute a c application as is, unless you limit yourself to one architecture and most likely one operating system. Java doesn’t have that restriction. Nor is java limited entirely by sun (yes, it is to a degree). Lots of other companies have made jvms for their architectures and as the free vms get farther, it will get even better.
Imho, with regards to his sample app, the most important factor in determining which language to use is where you want to use the app. If it’s extremely memory constrained, then maybe a jvm is too much. If you’re trying to incorporate it into an existing java app, any performance gains are no where near worth the trouble (and security hole) of going with jni.
I’m not sure why one would use anything but c/c++ for libraries… Simply for ease of portability to other languages, but also as he mentioned minimum nested dependencies (besides, the best high level languages provide their own, fairly complete, libraries; and use of other libraries is probably by advanced programs or niche programs).
IMO, he’s totally wrong on memory consumption. A well written program in anything, including java, can be just fine on memory consumption. And when you compare it to a graphical (obviously, console programs are a different bear) program in c you’ll find similar memory consumption (because the GUI toolkit will suck RAM up). Of course, embedded code is another story; if Sun had its way your embedded code would be Java running on a Java machine
.
Speed is also a load as well. For most programs, a loss factor of 100% is not noticeable (your GUI toolkit will suck far more speed than most of your program). The little bit of benchmarking I’ve done indicates that Java is VERY similar to c for arithmetic performance… Python is about 30 times slower (I still prefer the language though).
People discount c as a waste of time too often IMO. It may not be faster or less memory intensive. But in the end, all these quick fix things to fast productivity seem to end up producing buggy code: “Oh, I have a garbage collector so I can write: strcat(z,strcat(v,strcat(x,y))) (a modified strcat that returns the pointer to the ‘’ and allocates memory).” Then they do that, and it’s not wrong; but they end up getting sloppy and not going back over their logic once they’ve written it.
Don’t get me wrong: Garbage collection is great, because it’s plenty efficient and saves you something like 2% of your time; and moreover, it further narrows down every problem you have (you know it wasn’t that you freed to early) which probably does save significant time.
I don’t think the cost of writing something in c verse another language is that great (at least not for a medium sized program). But I do hate it when people use pre-processor macros for things other than constants and compile decisions!
I think the best thing is almost invariably some combination of languages. For example, write your program design in something like python, and all your work code (support libraries) in c… Then you can easily change major program logic, and have fast localized c code for calculations!
First he does a decent job listing reasons, why C has still it’s place today and I totally agree to the first part of the article although I really don’t like C anymore although or rather because I’m maintaining several C/C++ projects, memory errors and long compiletime are really bad for your productivity…
Just what shocked me was that he showed a freecell solver as a good example for C?!? Except speed none of the reasons he listed earlier applied to this project and if you’re heavily using the C precompiler, then this is usually a sure sign of premature/too much optimisation or trying to extend the language with new features. Anyway without a java or ocaml version of the solver to compare with his points are pretty pointless. You don’t necessarily need preprocessor hacks or pointers for fast programs (at least he would have to prove the contrary)!
I agree with you that the Freecell Solver coverage is a weak point of the essay. However, as I note in my site’s containing page ( http://www.shlomifish.org/philosophy/computers/when-c-is-best/ ), I could not convey the fact that as far as Freecell Solver is concerned, not only will writing it in a different language than C will be much slower, but it will also feel wrong. (and it will).
The reason I gave Freecell solver as an example is because it’s a project I headed (and thus am very familiar with it and can testify for it), and because I think C is the ideal language for its problem domain. I daresay I was not very successful.
::not only will writing it in a different language than C will be much slower
That is an unsubstantiated statement.
:: I agree with you that the Freecell Solver coverage is a weak point of the essay.
Very weak indeed, first you go talking about portability… and the first thing one finds when downloading the source is autoconf… you dismiss you own point.
And then, autoconf is not enough… for instance it does not build out of the tarball on MacOS. Very simple to fix but still weakens even more the portability argument. Why does not it build? Simple enough, while claiming that C code is portable because there exists the ANSI C spec… you go and do:
# include <malloc.h>
Which is not part of ANSI C. Dear sir, malloc’s() prototype is part of <stdlib.h>.
Not only that but all you header files are guarded by macros that start with a double underscore… but all such identifiers are reserved and should not be used by programs (see section 7.1.3 of the spec.) Another portability problem since those identifiers belong to the compiler, not to you.
:: but it will also feel wrong. (and it will)
:: …
:: because I think C is the ideal language
Opinions do not make facts.
What it sounds like you’re saying is, “Gee, if everyone just wrote their programs for x runtime, everything would be peachy.” Isn’t that the same as arguing that everyone just write for x hardware architecture, and that will solve all portablity problems?
I don’t think moving the portablity problem from hardware to x virtual machine is a silver bullet. It just moves the problem somewhere else. Porting VMs is sometimes more difficult than just porting the program that would have run on it on the first place.
Endiness isn’t that big of a problem. You have what: two possibilities? Most portability problems in C result from misuse/understanding of types or making broad assumptions.
Also, null terminated byte arrays are a library convention. It’s not a language feature. If you want to manipulate unicode, use the proper library.
Now, don’t go on a flame fest just yet. I don’t advocate using C for large application programs. I’m definately in the python/lisp camp; however, I don’t blame C for begin deficient for features (or the lack of them) that were specifically meant to model the hardware closely. Richie wasn’t a moron after all.
Endiness isn’t that big of a problem. You have what: two possibilities?
And why on earth would I want to use a language that lets the programmer deal with it instead of doing it itself? I can’t think of any situation where as a programmer you would want to have the endianess differences exposed to your programs (not even in drivers). Just make everything be big endian in source code level and let the compiler figure out how put that in machine language.
Also, null terminated byte arrays are a library convention. It’s not a language feature. If you want to manipulate unicode, use the proper library.
So, no portable strings in C? It’s only portable when I rely on the standard C library, which uses null-terminated strings. When I have to rely on other libraries, I lose the (supposed) portability.
> Just make everything be big endian in source code level and let the compiler figure out how put that in machine language.
And how do you “make everything be big endian”, exactly? 🙂
> And how do you “make everything be big endian”, exactly?
Have the compiler “correct” my bit-shifts and char* casts automatically on little-endian platforms. Having not to deal with machine-specific issues and not having to reinvent the wheel for string operations is the whole point of why one would want to use a high-level language instead of assembly.
I don’t see how you can call a language “portable” in which the exact source code can returns different results on PPC and x86, even when compiled with the same compiler. And if you think endianess issues never happen, then you have never dealt with UTF16, raw PCM audio or bitmap data.
> Have the compiler “correct” […] char* casts automatically on little-endian platforms.
With pointer arithmetics from a parallel universe?
>With pointer arithmetics from a parallel universe?
Nah, alien technology is sufficient.
When Basic, Java, PHP, Python etc allow me to byte-wise iterate through memory in big endian on a Pentium, why should C not allow me that?
> So, no portable strings in C? It’s only portable when I rely on the standard C library, which uses null-terminated strings. When I have to rely on other libraries, I lose the (supposed) portability.
If you change an API, I have to admit it is quite hard not to change the program…
And why on earth would I want to use a language that lets the programmer deal with it instead of doing it itself? I can’t think of any situation where as a programmer you would want to have the endianess differences exposed to your programs (not even in drivers).
You’re going to want endianess differences exposed whenever you’re dealing with a binary encoding. This includes various binary encodings for network protocols, video and audio encodings and even the bytecode which a JVM or .Net runtime needs to decode. If the compiler automatically enforced the endianess of the hardware (and some hardware allows you to change the endianess, what then?) how would you go about encoding or decoding such binary protocols?
Besides encoding and decoding binary protocols, when would a programmer even worry about endian issues anyways? I can’t think of one time that I was actually bothered by that in normal application code.
> If the compiler automatically enforced the endianess of the hardware how would you go about encoding or decoding such binary protocols?
The way you would do it on any big endian machine.
>(and some hardware allows you to change the endianess, what then?)
Are you talking about the PPC? Besides the fact that I have never ever seen any reason why you would want to do that during the runtime of a program, you’d usually have to write separate code for such cases – when your compiler abstracts that, the compiler would just to what the PPC itself does – Wikipedia tells me that “in Little-Endian mode, the three lowest-order bits of the effective address are exclusive-ORed with a three bit value selected by the length of the operand”. If you really need to switch the target platform in the middle of the code (is there any compiler that supports that at all?), you’d have to introduce pragmas anyway.
And why on earth would I want to use a language that lets the programmer deal with it (snip)
Any C programmer worth her salt would use htons/ntohs/htonl/ntohl when endianness is an issue. In practice, it rarely is.
Well, I believe things like strcat are defined in ansi c, and they use null terminated strings.
However, most of the ansi-c libs are tiny and pretty easy to rewrite. So yea, you could certainly define your own string struct and libs to deal with it.
I think if you’re having an endiness problem, well, QUIT USING THE SHIFT OPERATOR; or prepare to write that code over for every platform (not that big a deal).
Yeah, when you’re just comparing to C to Java, C becomes pretty attractive. I guess I’ll agree that when it comes to libraries C still has the advantage of maximum potential usability.
There are some comments, but many of them may be out of date. I happen to agree with the Extreme Programming camp that it is really better to refactor and make the code easier to understand than to comment redundantly.
Not keeping comments in sync with the code (either by updating or by deleting them) is just sloppy. Referring to the XP refactoring technique is nothing but a cheap excuse – some code is just too complex to stand without comments, and the threshold for that is much lower than most programmers are comfortable to acknowledge.
This doesn’t give me much confidence that Mr. Fish actually knows what he is talking about.
Most portable language? I’ll bet that 95% of C code of 10 years ago doesn’t compile with the latest gcc.
Berend.
First, the ANSI C spec was written before unicode was in wide spread use. If the spec was amended to include dealing with unicode strings, you’d have perfectly portable C unicode strings.
Second, what you really want is everyone’s architecture, operating system, and programming APIs to be identical so that everything is ultimately portable. I can’t say that will never happen, but I’d be willing to bet that it’s highly unlikely. I don’t even think its desireable. Sure, it’ll make thing easier now (in the short term), but it’ll ensure that we’re on a path to an evolutionary dead end.
I don’t believe that programs need to be portable amongst operating systems as long as protocols are open. Sometimes this might be false, but I think that really brings you to the ultimate conclusion: THERE IS NO SILVER BULLET.
There was an interesting comment, it’s from a “LAMP” guy about portability. He’s advocating a new development platoform based on, I think, PHP. The guy used to be high up on the Sun App Server team, can’t think of the name.
Anyway, he basically made the thesis that portability is simply a red herring. When everyone is running Intel/Linux, portability is no longer an issue.
This is a similar theme used by many advocated for single sourced languages (like Python or Perl), and how there code is more portable than, say, Common Lisp is. Since all of the language implementations are essentially the same source based (there is but a single Python interpreter, for example (modulo Jython)), Python code is therefor more portable across platforms than Common Lisp, since there are few cross platform, single implementation CL’s out there (CLisp is the most prevalent of the free ones I believe).
So, by the same token if you limit your enterpise to Intel machines and Linux, then you have no portability problems at all. Yet, due to the large variety of configurations that Intel/Linux provide, you don’t really lose anything by constraining yourself to that platform, so what benefit portability if the given platform is so capable?
I think he has a point, though I would in fact argue that the most flexible platform in terms platform would be Solaris/Sun, even though they’re a single vendor, given that your code will work on their lowest end 1 CPU boxes as well as their super duper 64 CPU monsters. If you stick to source code portability, and follow their published guidelines, Solaris source should port readily from SPARC to x86 (running Solaris x86, of course).
But, in truth the Intel/Linux argument is strong. Save for a monster mega multi-CPU behemoth room heater to run, say, Oracle, there is very little the Intel/Linux platform can not do today.
Of course, this has been the MS argument for some time. No need for portability if all you wish to run is Windows.
Well, I have to say this essay is mostly B.S. designed to support someone who obviously has an unreasonabe bias towards C (unreasonable that he is willing to use B.S. to support it)
First, the portability issue. You do NOT rely on Sun’s whims. In case the author hasn’t noticed, there are plenty of other vendors that make implementations of Java for tons of platforms–including three open source projects in the works to produce open source Java implementations. Also, on the portability issue, I can pretty much guarantee the author that for a complex application, I am going to have far fewer portability issues writing it in Java than in C.
“You cannot effectively duplicate a struct containing other structs in Java or in Perl as you can in C.”
Why not? The only difference is you have to use a class.
“You cannot work with interrupts, DMAs, and other hardware elements”
…But what happenend to that portability he was just touting in your last paragraph?
“Many problem domains call for ANSI C”
No, they don’t. Only very low level problem domains call for ANSI C, and domains where squeezing the absolute maxiumum possible performance out of a system is critical. The rest of the time, it is not worth the 5 to 10 fold increase in development time and the even larger increase in debugging time thanks to stale pointers, memory leaks, and other memory issues which are the single biggest cause of persistant bugs in production software.
“There’s no fork() in Java, and not many other UNIX system calls.”
And there are no threads in ANSI C or the C standard library. And threads are much more useful and lighter weight for most purposes. Certainly you can use third party libraries to add threads to C, but that creates lot of portability headaches. And I can also use JNI libraries to get fork() in Java… But since he brought up fork() and other system calls… So much for that portability he was touting earlier.
“Many real-time applications (i.e: applications that should respond to events within a given time) must be written in a low-level language for that reason.”
Really? Tell that to Boeing, who was showing off a completely automated reconnaissance aircraft at JavaOne that requires no human pilot and no human intervention, and can automatically update it’s flight plan based on what its cameras and scensors see in real-time battle conditions. It’s “pilot” is written in Java. Or maybe tell it NASA, who decided that Java was suitable for writing the Mars Rover software.
The abililty to respond to events in a given time is critical yes, but that’s what Real Time Java is for. But there is something else that is usually critical in these real time applications as well, and that is reliability and robust fault recovery–areas where Java shines but C is severely lacking because of its lousy error handling facilities and lax stance towards ensuring that potential errors have been dealt with.
“Now, how do we do it in Java? In Java every reference to a structure or an array is allocated and manipulated individually. We cannot have them chained one by one in memory.”
I’m not following his logic. This sounds to be nothing more than an array of pointers to structs, or what in Java, would be an array of objects. In reality of course, in Java, the array does not contain the objects themselves, but only pointers to the locations of those objects. So I’m not sure what he means when he says the references can only be manipulated individualally, and cannot be chained in memory. That’s simply not true.
Overall, this essay is mostly B.S. from someone who is either very uninformed about Java, or who is intentionally putting a huge spin on things to support C.
For a much more informative discussion of why C is usually not the right choice to start a new application today, and of the few times where it is, see Art of UNIX Programming, by Eric Raymond, which is available online.
First of all, I’d like to point out that the article’s writing style is atrocious. I’m especially offended by the use of non-words like “open-sourcability”. Its good to use parallel constructs in your titles, but you don’t get to cheat in the process! Moreover, even if “sourcability” was a word, it wouldn’t mean what the author obviously intends it to mean. Rather, it would mean that it is easier to put C code under an open source license than other code.
ANSI C is portable for every architecture there’s a gcc backend or any other compiler for.
As a result of the fact that many Lisp-like languages compile to C, this is equally true for them.
gcc is a full-featured and robust compiler for ANSI C, and it’s open-source.
And CMUCL is a full-featured and robust compile for ANSI CL, and it’s open-source. The point being?
You cannot effectively duplicate a struct containing other structs in Java or in Perl as you can in C.
But you can in Lisp! Or Dylan. Or Scheme. Or Ocaml. Or a dozen other languages!
You cannot work with interrupts, DMAs, and other hardware elements.
C has no conception of interrupts, DMAs, etc. Indeed, you *cannot* generally write an interrupt handler entirely in C without extra-lingual mechanisms. On x86, this is due to the need to use IRET to end an interrupt. Implementations of any language could include such functionality.
You can compile a C library and distribute it as is.
Only if you link it statically. On the other hand, you can do the same for a statically-linked Lisp/Dylan/Scheme/ML app too! The machine doesn’t care what language the binary originally was!
There’s no fork() in Java, and not many other UNIX system calls. You need to create bindings for them (which require JNI) or work around them.
The need to create bindings is:
a) Trivial, thanks to auto-generators.
b) An artifact of the fact that the system is implemented in C!
A C library can be used by Perl code, Python code, Tcl code, Ruby code, to a lesser extent Java code, etc. Code written in a high-level language is mostly usable only in that language.
This argument is completely true, and the only decent one in the bunch. System libraries, on *NIX, should be written in C. C is so primitive that its easy to bind any language to it, and accessibility should be the primary goal of a system library.
Other applications like that are applications that simply can never be fast enough: various APIs, virtual machines, simulations, graphics, audio, video and 3-D programs, etc.
This is argument is only partially valid. Real-time control apps can (and have been) written in high-level languages using a real-time GC. I do, however, find it entertaining how many people think that C gets you most of the way to being real-time. Most code written in C is *unsuitable* for real-time use. Most C code uses memory management techniques (eg: reference counting — it’s everywhere, even in the Linux kernel), that are unsuitable for real-time systems. Most C malloc() implementations aren’t suitable for real-time systems either. Writing real-time code is hard, and given a good real-time GC, isn’t particularly harder in a high-level language than in C.
As for simulations, they can be written just fine in high-level languages. The nice thing about most simulations is that they are generally quite parallizable. You don’t really care if the code is only half as fast, because buying twice as many machines to run it is cheap. Indeed, if using a high-level language allows you to spend more time making the code parallelizable, even if the code is half as fast, it’s a net performance win!
Graphics and 3D code may or may not be unsuitable for high-level languages. Graphics code tends to have tight inner loops that are relatively easy for a VM or compiler to optimize. The JVM is particularly good at optimizing numeric algorithms written in a very low-level style (so is CMUCL, actually). For 3D code, the CPU performance question becomes almost a non-issue. Most 3D processing these days happens on a GPU, so as long as the main program is fast enough to bottleneck the GPU, it’s “fast enough”.
The real advantage of C is that a single C shared library can be used by your C++/Java/Perl/Python/C#/etc. programs, which saves memory and limits security. In other words, C plays nice with other languages.
Try writing a library in Java. Sure, it will be faster to write it in Java than to write it in C. However, it doesn’t help someone who wants to do the same functionality in Python; so the Python guy writes a similar library inj Python from scratch. Then the Ruby, Perl, Lisp, etc. people also write independent but similar libraries. You end up with 10 different virtual machines running on you computer, each one doing basically the same thing, but since they cannot share libraries, they take up massively more memory than they ought to. (And no, .net is not an answer — not if you want to use the .net assembly in a program running on a JVM)
Basically, if you are considering writing a library, <em>write it in C</em>. Or C++ if you really hate C. That way, everyone can use your library, and the world becomes a better place.
Obviously the author doesn’t know enough about Java to compare.
Lets face it. Java, Python, etc, are high-level languages and are doing a great job in this domain. They help developers get the job done fast. Of cause there are always room for improvement.
As for low-level languages the picture is a lot worse. Basically C is the only well supported choice (C++ is just a joke IMO). Now C is really a pain when you want to do larger projects. It was never designed for this. Despite this, a lot of hacks (preprocessor, automake, autoconf…) have made it possible to do larger projects.
SUN did a cleanup of C++ and made it usable high-level language (Java). This is really what C needs. It needs a cleanup that makes it a modern low-level language. While doing so a lot can be learned from Java, etc. I.e., I would like to have the compile speed of Java (yes it is fast when you subtract WM overhead. Look at Jikes). Also, Java has given us a lot of performance improvements that might be of use in a low-level language.
My point is that high-level languages have seen a lot of improvements in the last decade while low-level languages haven’t. D is an exception, but IMO its target is too wide. It’s not focusing on being low-level. Please tell me if you know other projects that are serious in improving the low-level language situation. I might have missed something…
I was just reading Rob Pike’s excellent paper “Notes on Programming in C”; short, clean and concise; and most of it can be applied to almost any programming language:
http://www.lysator.liu.se/c/pikestyle.html
C still is one of the most clean and useful programming languages; it’s the perfect “portable assembler”. But I must admit that this days when I want to do high level programming I prefer Limbo ( http://www.vitanuova.com/inferno/papers/limbo.html ) or Erlang ( http://www.erlang.org )
Good Lisp implementations have existed for both Lisp machines and C machines. Good C implementations have never existed for a Lisp machine. What does that say about C’s vaunted portability? You’re basically saying: C is portable as long as you only try to port it to machines designed for C. Duh. Does that mean it is portable, or does that merely mean that it’s so popular that most machines are designed for it?
Or it could mean that Lisp machines are one trick ponies. 😛
As I clarified, one could easily write a Java VM for a Lisp machine. Heck, you could write a Lisp compiler for the Java VM (and people have). Yet, you cannot write a conforming C/C++ compiler for either. The basic fact is that C makes the assumption that the hardware is unsafe. Higher-level languages make no such assumptions. Since only a subset of machines are unsafe, only a subset are capable of hosting a conforming C compiler, and therefore, C is strictly less portable than a number of other high-level languages.
Endianess is only relevant during I/O operations that span architectures. For example, reading a BE file on LE hardware, reading network packets on LE hardware, etc.
It is important to realize that it is programmers that make porting hard, not the language that they use!
In Game Programming C++ is now considered the standard language to use. True many games have scripting languages built into them (mainly this helps the development process, it means that designers can use the script without bothering the programmers too much) but the bulk of a game is still in C++. Why is this? Because there is nothing better out there for Games. Nothing is advanced enough, fast enough and mature enough. Every language has its place, anyone who argues that one language is better than another is ignorant.
To say “every language has its place” is almost tautological. The question isn’t “does every language have a place”, but “how big is the place for every language?” Moreover, the original statement is certainly no basis for the conclusion that one cannot argue that one language is objectively better than another.
Ultimately, a language is a tool. Tools can be compared, not just for specific tasks, but in general. Very few people would argue that a silicon-carbide drill bit isn’t better than a regular steel one. A steel one will serve you just fine for making holes in cherry, but the silicon-carbide bit is “better” using objective metrics.
The metrics are what’s important. The problem with most proponents of C or C++ is that their metrics are skewed. The only two metrics by which either of these languages will win comparisons are either performance-dominated ones or ones dominated by questions of cross-language compatibility. Moreover, even the performance-dominated metrics must be qualified to include “highly-tweeked” performance, because in many cases the fact that higher-level languages make it easier to implement fast (and therefore usually complex algorithms), offset their constant factor performance-losses. This wrinkle cannot be underestimated. It is precisely the reason that there exists massive amounts of slow software programmed in supposedly “fast” languages. For the vast majority of tasks (with games possibly being a genuine exception), a metric of this nature is unrealistic. Most software (remember, 90% of software is never shrink-wrapped!) doesn’t care about constant factor performance losses. It’s usually important, but usually, time-to-market, development cost, ease of maintainence, etc, rank higher.
The mentality of “only speed matters” is fading, and good riddence to it. It has dominated the industry for far too long. If your average C/C++ programmer designed airplanes, a 777 would go at Mach 6, but have a range of 1000 miles and cost a billion dollars per flight to operate!
The mentality of “only speed matters” is fading, and good riddence to it. It has dominated the industry for far too long. If your average C/C++ programmer designed airplanes, a 777 would go at Mach 6, but have a range of 1000 miles and cost a billion dollars per flight to operate!
Reminds me of how much it cost to fly to the moon.
But I ask you this, name one single language that is better than C++ for writing games in? This is assuming that you want the current or next level of graphics speeds.
I think this guy should’ve named the article C vs Java, because he is constantly refering to Java and not O’Caml/ Haskell/Perl/Python/PHP/Ruby/Tcl as he introduces…
Two CS freshmen up hacking all night
hacking all night
hacking all night
Two CS freshmen up hacking all night
hacking all night
hacking all night
Gonna hack
Keep hacking
Gonna hack
Drink caffiene
Gonna hack Gonna hack
Gonna hack Gonna hack
Gonna hack Gonna hack
Gonna hack na na na
Enh enh enh enh enh enh
na na na
Enh enh enh enh
You think you’re a programmer?
Well you’ve never used a debugger before
You’re a newbie! Here’s news, kid:
If you wanna hack code you need to debug it
’cause your code will have bugs and you’ll need to fix it
So your process is stopped on an infinite loop
On some operation where an iterator’s not incrementing
And when you fix that bug you get segmentation faults
’cause your strings are not NUL-terminated
Hey! It’s no time to get frustrated
’cause your CS 10 course left you uneducated
I know your boss wants it done tomorrow
So here are some programming tips you can borrow
When you’re doing something this easy
The bug won’t be in gcc
So try to track it down with gdb
And I hope you compiled with -g
So, come on kid, print out your listings
Sit down, load the core file and fiddle the bits
Set breakpoints, and check all your branchings
And check all of the values in memory
Now if you want to hack in C
Then you’d better learn gdb
’cause you’ll dump core eventually
And I hope you compiled with -g
I said, if you want to hack in C
Then you’d better learn gdb
’cause you’ll dump core eventually
And I hope you compiled with -g
Little hackers, beginner programmers
Embarassed your teachers are still using Windows?
You don’t need Linux to find out why you’re crashin’
Use CygWin or MingWin and pretend it’s a penguin
Dev-CPP’s a nice IDE
It’s not Anjuta, but it works for what you need
No floppies, keep your software on the ‘net
And get it with Putty ’cause you don’t know CVS
A bash script can’t necessarily
be used on tcsh or ported from Be
And Perl? It’s like blowing in your modem
*pfft* — look, it’s a regex! You can’t debug that
And nobody can write standalone apps in PHP
Does anyone even use Python or Ruby?
There’s no reason to code in assembly
These days when you can do it in C
*pfft* Attention PHBs
C++ is something you don’t need
Too complex, you might as well use C
printf() just has cout plain beat
Now if you want to hack in C
Then you’d better learn gdb
’cause you’ll dump core eventually
And I hope you compiled with -g
I said, if you want to hack in C
Then you’d better learn gdb
’cause you’ll dump core eventually
And I hope you compiled with -g
Now Visual Basic’s a piece of shit
Even the data validation functions crash
in it, a piece of trash language
ASP’s begging to have your website hacked
And Java? It runs as fast as lava
The VM takes an hour to load
And configuration, you get write once, run nowhere
The FHS ain’t that hard to follow
And C# is an obvious ripoff
Its Java without the interoperability
So big deal, it does XML like everything else
MS sycophants pretending it’s something respectful
There are some times it seems to me
That everybody ought to hack in C
This must mean that C is neat
And C is not yet obsolete
Hey, I’m not saying that C is supreme
It lacks garbage collection and some other things
Just know what language features you’ll need
And use whatever will provide these
So hey, here’s a concept that works
Twenty million computer languages emerge
But no matter how well they fit your needs
There will always be a place for C
And if you want to hack in C
Then you’d better learn gdb
’cause you’ll dump core eventually
And I hope you compiled with -g
I said, if you want to hack in C
Then you’d better learn gdb
’cause you’ll dump core eventually
And I hope you compiled with -g
Na na na na na
Na na na na na
Na na na na na
Na na na na
Na na na na na
Na na na na na
Na na na na na
Na na na na
http://hamburgsteak.sandwich.net/writ/laugh/filksongs.txt
A lot of development now only calls for a very high level language and doesn’t deal with a great amount of memory management.
If you are concerned with endian matters, use Sun’s XDR (external data representation) libraries. These can be extended by the user to cover any anticipated c-structure.
I written C APPS for both winodws & UNIX. Simply put, while the language is the same, everything else is different. The author shouldn’t talk until he has done a real project… one that lets say, you get paid for…
Yet, you cannot write a conforming C/C++ compiler for either. The basic fact is that C makes the assumption that the hardware is unsafe. Higher-level languages make no such assumptions. Since only a subset of machines are unsafe, only a subset are capable of hosting a conforming C compiler, and therefore, C is strictly less portable than a number of other high-level languages.
This argument has so many holes, it borders on nonsense. In no way does C assume a “unsafe” machine, for a start. You are almost sitting in front of the prove: Assume you have a machine which you deemed “safe”. Plug this machine to your normal desktop computer (which you call “unsafe”) via serial port and the keyboard connector. Let the safe machine just pipe through input and output of the unsafe one. Let your C written program execute on the unsafe machine. The result is a safe machine which can execute a C program. The only remaining “problem” is that the C program might never terminate. I do not know if your definition of a “safe machine” does include that it always terminates. But if it did, it could not run Java either.
By the way, I could make a similar nonsense prove like you did myself. It could go this way: Java assumes a graphic screen to execute, C does not, so Java is strictly less portable than C.
This is one of the only webpages where I’ve had to turn off page styles in order to read it – yikes!
I take issue with most of the article (as does everyone on this thread, it seems), but particularly the argument that C is inherently portable. I’m sure there are platforms without a libc where there’s e.g. a java VM (I’m thinking some specialised phone situations, for example) – you just forget you need libc since it’s so often there. Lovely also to have portability argued within the vacinity of ‘UNIXisms’
C is portable enough. It’s not even desirable that anything be portable. Programs should be running the most efficiently possible on the hardware and platform they’re designed to run on. If you disagree you’re either:
1) lazy
2) incompetent
3) a capitalist
I take issue with most of the article (as does everyone on this thread, it seems), but particularly the argument that C is inherently portable.
Well, then take issue. But C is portable, that is a fact. The proliferation of C-implementations is proof.
I’m sure there are platforms without a libc where there’s e.g. a java VM (I’m thinking some specialised phone situations, for example)
First, you are comparing apples to oranges. The counterpart of the C library is a (subset) of the Java SDKs library. The counterpart of the JVM would be a C-compiler without the libc.
Second, your statement, even if true, does not contradict the notion that C is portable. If you have 60 platforms where you have at least C, and only one platform where C does not run, than C is still portable.
Third, you neglect a certain technicality, which is that C does allow a so called “freestanding” implementation, which does not even have large parts of the libc (Of course, programs using the libc will not necessarily run on that implementation).
Fourth, guess in what language is the JVM written in, which you suppose exists for that phone? Hint: It is not Java (-Well, okay, it is unlikeley that it is Java).
[ joke ]
Why use C, it’s slow and the so high level coding is overkill.
With ASM, you’ve got simplicity and Speed, and you control exactly what you done with your program.
When you need to pull out every single cycle from your proc, there are no other choices, C is too much bloated
[/ joke ]
That was the typical rant in the 90’s against C for gaming on the 68k, i386 processor generation.
Now who cares, coders are waiting the next gen CPU/GPU/PPU/whatever.
Now only the console coders must times to times optimize in asm for a given hardware architecture to “pull out every single cycle from the hardware”.
In 20 years, we will have the same arguments between java (wich will be a low level language) and a “yet to define” higher order language.