What’s to love about C?
mortoray.com
mortoray.com
( Yes I know you can s/C/ASM , however this is a time issue eventually we may get past needing C , but we are not there yet )
I agree. Anyone who's going to be working at a non-entry-level job in the computer industry should know what the foundations are built on. C still dominates in the kernel space and other low-level facilities everyone uses. If you don't know it, you are at a disadvantage compared to those who do.
Where do these delusions even come from? I think a lot of people here would benefit from 6 months in a 'normal' company, the kind that employs the vast majority of programmers. Just for a bit of perspective.
That is true. Most programmers will not need to write code in C. But they'll still be better and more versatile programmers if they know the language.
I agree, although I'm not sure C should be the top priority for someone that will never need to actually use it. There are lots of other things to learn and nowhere near enough time to learn them all.
Although learning C when you already know other languages is not particularly difficult.
Probably from those of us who have found a working knowledge of C fairly useful in their careers?
I've been working for 24 years in software and I'd say that during most years I've written or read C sources. Some years it would be a lot, some years relatively little, but it's been a very useful skill for me.
I agree that relatively few people need to write C these days - but knowledge of it does, in my opinion, help quite a lot.
Also, C isn't a complicated language. Like any, it has faults and warts, but it's pretty damn elegant on the whole.
C++, on the other hand... don't get me started.
If you had said 99.9% of programmers should not write C, I'd agree. But the reality is there's a lot of numb nuts out there, and you're going to need to fix their code. If you can't beat em, join em.
I honestly don't get this attitude in our industry. Nobody tells a general practitioner, "Nah, you don't really need to know what comprises a living cell. You most likely won't even need to drop down to that level."
Just because you don't need to do any low level work, doesn't mean you shouldn't learn anything about it.
If you think most programmers who know Java, C#, Ruby or, Python have ever dropped down to C you're deluding yourself. And they never need to and not only that the majority of their performance problems come from poorly written SQL queries. And the rest come from poorly conceived loops.
As I said, go get a job in a normal company, open your eyes. Most job applications will not give you an advantage if you put the ability to drop down to C on your CV. Because they will never, ever, ever need it.
I've worked several years at a normal company. My group of dozens of software engineers codes overwhelmingly in C, with Python, Perl, Lua, and the occasional ML in support roles.
I think a lot of people here would benefit from 6 months in a 'normal' company, that employs the vast majority of programmers. There's so more to the universe than Rails, Django, and JQuery...
I agree.
The world of software is built on layers of abstractions. Both the skill of effortlessly layering abstractions and also the skill of peeling them away are fundamental to deep programming and modelling skills. Languages like LISP open the door to effortless modelling, whilst a language like C strips implementation all bare.
Its nice and widely available, fairly neutral on programming style (in the imperative space - few "political" (eg objects) abstractions rammed down your throat that don't actually exist in the CPU).
It can be used in a semi-portable manner, and inter-operates easily with assembler as required.
Boxing, GC, forced classes, and so forth still are not free. They are close to free in many problem domains - but you cant make them go away in other languages when they get in the way.
A good programmer has the mentality "it's all turtles, all the way down", where a turtle means a thing that ultimately is just a piece of code, written by someone much like yourself, than you can understand inside out if only you take the time to do so. Even the CPU is just code (e.g. VHDL).
I spent the next few months at the console (configure X, what am I a god?), with emacs, and gcc and it was glorious.
I still remember the day when I figured out I could declare a function in one place, and then define it in a different .c file, compile things individually and link them and it would work!
So yes, I agree I think everyone should learn C, since it's still the best, thinnest model for the Von Neumann architecture a typical computer provides you. And those early painful steps with C have really served me well when it comes to visualizing the mechanics of a problem
So here's my counter-claim. Most Java and .NET developers will do just fine without knowledge of C.
Above and beyond the practicality of being able to extend your language or debug it when it brakes in new and interesting ways, you also just have the general knowledge of how computers work that much more. This isn't to say you aren't any good, but if you want to be that much better you should learn C.
GUIs may still be a different matter, but I haven't programmed them in .NET/Java in years.
Furthermore not C directly but they should know how programs link and execute
I like how C is fast and dangerous, there's no silly security layers (like Java) and it lets the operating system do it's job. Fast stack allocs for temporary data are great but deadly if you fuck up.
Coding in C is like carrying a loaded gun pointed at your feet. You have to handle it with care and responsibility but when you need it, you can shoot away any extra limbs that get in the way and show 'em who's the boss.
C is a great language for many reasons, but let's not conflate benefits.
*NIX is the same.
Python is fun, but I've got no idea how it is doing what it does.
That happens quite a bit these days for me.
Urf tell me about it. Does my flipping head in.
I managed to get one of Michael Abrash's (ID software)loops to run 0.5 clock cycles faster, which I was pretty proud of.
There's a lot of undefined behaviours to know about, and not all of them are obvious. You can be merrily compiling your programs fine on GCC and Clang and your intended behaviour seem entirely obvious, only to have it blow up on another compiler or with some different compiler flags.
That said, the undefined behaviours do allow the compilers to do some very tight optimisations, so swings and roundabouts.
"Decent test harness" is like "sufficiently smart compiler". Everyone assumes it will be there when planning, but in practice it is only available in very specific and not-generally-useful cases.
$ cparser -O3 -Wall -Wextra -pedantic test2.c -o uninit
warning: ignoring gcc option '-pedantic'
test2.c:3:6: warning: no previous declaration for 'void foo(int)' [-Wmissing-declarations]
1 warning(s)
test2.c:4:6: warning: 'variable lol' might be used uninitialized [-Wuninitialized]
Looking at the GCC bugtracker, there seem to be various warnings missing. http://gcc.gnu.org/bugzilla/buglist.cgi?quicksearch=uninitia... clang -Weverything uninit.c
uninit.c:3:6: warning: no previous prototype for function 'foo' [-Wmissing-prototypes]
void foo(int bar) {
^
uninit.c:10:6: warning: variable 'lol' may be uninitialized when used here [-Wconditional-uninitialized]
if (lol == 7) {
^~~
uninit.c:4:9: note: initialize the variable 'lol' to silence this warning
int lol;
^
= 0
uninit.c:37:3: warning: no newline at end of file [-pedantic,-Wnewline-eof]
*/
^
3 warnings generated. ==46592== Conditional jump or move depends on uninitialised value(s)
==46592== at 0x100000E90: foo (in ./a.out)
==46592== by 0x100000ED3: main (in ./a.out)
The matter is, valgrind exists. Everything is a C deficiency that valgrind is able to overcome decently is no longer a C deficiency practically speaking. * Lots of programmers you can hire today (contrast to D, ML, Haskell )
* Excellent introductory texts (Kernighan & Ritchie)
* Backed by giants like Microsoft, IBM
* Everything else always has some mechanism to link against it
* Thorough API documentation (if quite large) MSDN, man 3 sprintfWhacking variable declarations at the top of the scope becomes second nature quickly.
I came from assembly language, where the process is very similar and not too demanding
The particular example of reading a csv file is just a bad one to compare C and any dynamic language with, because in C file IO is a pain in the neck with a lot of pitfalls whereas dynamic languages make it lovely and you only have to remember a small amount. I guess it's a decent test to see if one's potential C coder has memorized all the details about C's file IO, maybe the company does a lot of that since they create libraries for others or something. (Did you allocate enough memory on the stack/heap? Are you reading byte-by-byte looking for a newline or in chunks before looking? Are you checking if you need to re-alloc? Do you support "\n", "\r", and "\r\n"? Are you checking for E_NO_MEMORY and E_BAD_SOURCE? Are you using sprintf safely? Are you checking for end-of-file correctly? Are you tokenizing the line properly? Are you faster than Python? Etc.) If the interview is just looking for coders who can "fopen, fread with malloc, and fclose, it's okay if details are forgotten", then it's just a weeder question rather than a skill test and there are better weeder questions.
Personally I have a handful of C programs on hand that I know are correct and that do various IO stuff, I tend to just copy from those on the rare occasion I need to use C to do manual file IO or memmapping (we all remember the subtleties of that right?) because of the reasonably high probability I'll forget one of the many details if I do it from scratch. I much prefer using already existing libraries to read and parse for me; there's too much reinventing-the-dysfunctional-wheel culture in C.
Most people can't open a file and read in the contents, forget parsing the contents just reading them in is where most people fail.
The problem with C is that, for all its simplicity, there's a ton of voodoo which you've got to "just know", and the best practices are not at all clear from what the language makes easy. In fact, the language makes it easy to make mistakes and difficult to find them.
I wish Go had made GC optional, I really do.
And then there's setjmp/longjmp.
Clear and unambiguous
Aside from all the undefined and implementation-defined behavior.
A macro preprocessor
Which just does plain, dumb text substitution with no understanding of program syntax (or the environment where the expanded macro will appear!). CPP's macro system is a pretty leaky abstraction.
The other points are why I use C (when I use C), but I wouldn't make these three arguments in favor of C.
Not even assembly language has this property anymore, especially in the presence of an OS.
Which leads me to what I think is C's greatest weakness: It's no longer a thin layer over assembly language. It is so far removed from the current trends hardware design it doesn't even have functions that implement memory barriers as part of the core language, let alone any language features to help you take advantage of whatever SIMD hardware the machine possesses.
Part of this is C becoming a victim of its own success: People expect the same language to compile down to ARM and x86-64 and IBM mainframe (zSeries) and so on and so forth machine code, and do it in an efficient manner. Since low-end ARM chips don't have SIMD, C can't have SIMD, the thinking goes (even though low-end hardware doesn't have FP opcodes, either, but floating-point math is still part of the C standard).
They rely on compilers to make it fast, which is reasonable to some extent but it's also the same thing you rely on when you write in Haskell. It's contrary to the spirit of things.
I'm not advocating a return to assembly language. That would be massively stupid. However, it would be nice to have a language with concise syntax that also allows you access to the processor's status word (the carry flag, for instance).
Implementation-defined behavior can be harder to avoid, but that's not a problem if you're targeting a known implementation.
True, but who is going to write your Python/Ruby interpreters then? And using what language?
Pythonistas will.
> And using what language?
Using python. Case in point, Pypy.
<\ :P>
Yes, PyPy is an excellent example of doing low level tasks in a high level language. It's also quite rare. I think in the future we'll see more examples of self-hosting dynamic languages that have a JIT-compiler based execution environment that combines interpretation and compilation.
However, in comparison to the stuff that the PyPy guys are writing, C programming is easy. And I bet all of the PyPy programmers are excellent C programmers, because they have to be good with low level stuff anyway.
I still advice learning C programming, and how interpreters and compilers work.
C is by no means my go-to language for personal projects, but there's still a helluva lot of software out there that it would be folly to write in anything but.
To some extent, I hope the code that gets generated isn't predictable in the way you mean: I want the compiler to know all of the obscure ways to make string operations go faster by using SIMD hardware, for example. I want that kind of deep low-level knowledge to be encoded into the optimization passes because I don't know it and I likely never will. Isn't that why we have optimization passes to begin with?
I'm all for people writing programs/apps in C++, but I kind of cringe when I see a library in C++ because it's a harder language to wrap around.
And hardware has changed. Remember, the C machine model (the virtual system you imagine in your head when you write C) doesn't have cache, doesn't have SIMD, and doesn't have any kind of ability to do things in parallel.
But I don't see how this is true. Pointer aliasing is the biggest example probably:
http://www.futurechips.org/tips-for-power-coders/how-to-tric...
And then there is the huge abstraction penalty for things like `qsort()` where C++ is actually way ahead of C.
Because it is so close to the lower levels of abstractions, it ended up a compact and concise language, easy to keep in mind. This (among other things) led to C being the quintessential language for some segments of "computer science": maybe not so much directly but as a reference model.
There's actually no such thing as a bad language. I enjoy language wars as much as anyone else, but languages are only good or bad relative to the type of problem they're being used for.
For example, what makes C++ and Java odious is that people try to use them for inappropriate purposes. They aren't platonically "evil" languages, and they weren't designed by stupid people; they're just inappropriate for over 90 percent of what modern programmers have to do in their professional lives. When people need high-level features and don't have them, they tend to roll their own-- badly. This is Greenspun's Tenth Rule and the heart of those god-awful "design patterns".
C++ and Java, for all that, also have domains in which they're the appropriate languages to use. They're just very small.
If it's irrational to reject multi-language solutions (I believe it is), why do people keep doing it?
I've worked on a number of mixed-language projects, and these same issues keep cropping up. Perhaps it depends on the team, but that is not something not everybody gets the chance to choose. My current mixed-language program (tcl/C++) is working out OK, with just me working on it, but tool support is poor, and hand-writing the language interfaces is annoying.
(Notable exception: Visual Studio 2010 looks to offer pretty decent mixed native/managed debugging, and the CLR has good C++ interop support.)
I haven't had the opportunity to try it yet, I only heard about it a couple of days after the last time it would have been really really useful (naturally). But I know it's going to come up sometime.
Now seems doubly annoying that Apple make you use lldb or crappy old gdb 6 for iOS.
The little bit I have seen of multi language code would say that that holds, especially if the languages involved are not C and something else(What does a Python dictionary look like in Haskell? Answer: Crap unless you do a bunch of translation work). Debugging tools don't tend to work across language boundaries. etc. Maybe I gave up to quickly, but multiple languages in one executable just doesn't seem worth it. Writing components in different languages and have them communicating over some sort of shared bus, web services, whatever is simple and fairly effective.
When the DoD started what became the Ada mandate, they had some insane number of languages and projects scattered about. I don't remember the exact number but think something like 450-500 and this was from the 1960s and 70s when they still weren't terribly digital. At the macro level, that's impossible to maintain. I think a large part of the multi-language dislike came out of that. There is a giant difference between 3-6 languages and 400, it's also harder to get good people once you add a new technology to the stack that they need to know. There are generations of developers and IT/IS guys that have been trained and warned of the dangers of polyculture. That's why people keep doing it.
But should it be?
I think it's probably a mistake to teach OOD/OOP in an introductory course and would rather see types, assignment, flow-control, etc. covered in a thorough manner. As it was, he ended up with big gaps in his general knowledge.
My rationale is that I can easily start just by letting the students type into REPL while they're learning basic concepts like assignment and operators. Classes are there when you need them but can be ignored until the students are comfortable with both the language syntax and the basic concepts behind programming.
I hate classes where the instructor says "just do this without asking why for now" ... and I learn best when I can experiment freely and iterate quickly.
I do think there are bad languages. Brainfuck is terrible. Maybe there are no bad serious languages, but you'll have to define what you mean by serious, and you'll have to argue with Dijkstra's ghost when it comes to COBOL et al. (though I think he would have liked J). (His two famous quotes against COBOL come from http://www.cs.virginia.edu/~evans/cs655/readings/ewd498.html) I don't think good/bad is really the best way to judge languages, I'm more interested in language power, fluidity, and library support.
I'd agree that every language has a purpose, even if the purpose is as simple as making a joke like in the case of LOLCODE, and that people abuse the language beyond its intended purpose. I read somewhere someone asserting "Design patterns are missing language features" and I more-or-less agree with that.
How well do you know PHP?
I do think there are bad languages. Brainfuck is terrible.
Brainfuck is not terrible, it's just not easy on human eyes. Brainfuck is really a very simple 8 instruction turing machine designed to have the smallest possible compiler on the Amiga (240 bytes, at that). It is actually a derivation of p'', which is a programming language from the 60s used to describe a family of turing machines.Now, for a truly terrible language, I introduce you the only programming language named after the eighth circle of hell in Dante's Inferno...
@@@@@@@@@@ @@@@@@ @@@ @@@@@@@ @@@@@@ @@@ @@@@@@@@ @@@@@@@@
@@@@@@@@@@@ @@@@@@@@ @@@ @@@@@@@@ @@@@@@@@ @@@ @@@@@@@@@ @@@@@@@@
@@! @@! @@! @@! @@@ @@! @@! @@@ @@! @@@ @@! !@@ @@!
!@! !@! !@! !@! @!@ !@! !@ @!@ !@! @!@ !@! !@! !@!
@!! !!@ @!@ @!@!@!@! @!! @!@!@!@ @!@ !@! @!! !@! @!@!@ @!!!:!
!@! ! !@! !!!@!!!! !!! !!!@!!!! !@! !!! !!! !!! !!@!! !!!!!:
!!: !!: !!: !!! !!: !!: !!! !!: !!! !!: :!! !!: !!:
:!: :!: :!: !:! :!: :!: !:! :!: !:! :!: :!: !:: :!:
::: :: :: ::: :: :::: :: :::: ::::: :: :: :::: ::: :::: :: ::::
: : : : : : :: : : :: : :: : : : : :: : : :: :: : : :: ::
EsoLangs wiki entry: http://esolangs.org/wiki/Malbolge
99 Bottles: http://99-bottles-of-beer.net/language-malbolge-995.htmlWriting programs in Malbolge is so difficult, typically one has to use another language to generate programs and search for a working malbolge program, or make extremely large programs that go on for pages.
You have been warned!
There is another axis of 'badness', other than suitability for the problem domain. C's main problem is features that look fine but might subtly invoke wrong behaviour - the infamous traps and pitfalls.
If you can accept this view, then there /can/ be such a thing as a bad language, and it can be possible for two languages to suit the same domain and one to be better than the other. The domain that C serves well is not going away (though it might shrink, as more suitable tools are used for things like compiler-writing), but a better langauge for the domain could come along in the end.
It's not a gui programming language. It's not a text-handling programming language. It's not a symbolic programming language.
But it's used as those, constantly.
Pointer-based errors are endemic to C; they ought to be an expected part of the language usage by now. There are reasons why static analysis tools such as Klocwork are out there, and are very expensive... and keep being bought. Because C is bad for an incredibly large range of tasks that it keeps getting used for. I've done some of that, and using C (or C++) made things harder and more error-prone.
It's also very good at other tasks... like writing OS kernels or drivers. I've done some of that, and C made it possible.
Although at this point, I'd be interested to give writing an OS in D a spin to see how it works.
I'm confused by what you mean. What is this "higher level" that functionality should exist at that is above libfoo.so?
Yeah, C is close to the metal. But only on a PDP-11, the assembly language of which C was conceived to integrate with.