45 years since its creation. The C language still very popular
javadepend.com
javadepend.com
Fortan: 59
C: 43
C++: 33
Python: 25
Php: 21
Javascript: 20
Java: 20
It's still a long time until any of those languages reach 100. But longevity seems to be the rule, not the exception. How many languages that were widespread actually died?[0] I don't pretend to know all the languages that have ever been popular, but not many that subsequently died come to mind. Cobol, maybe some lisp dialects, if you don't count Common Lisp as their successor? Is PL/1 dead? Was APL big enough to make the list?
Probably some of the languages I listed above will die before they're 100. Others might be niche, like Fortran already is. But I wouldn't guarantee it.
[0] Where dead doesn't rule out someone being paid to maintain ancient code. By that standard, it's unclear whether anything will ever die (https://www.snellman.net/blog/archive/2015-09-01-the-most-ob...)
Even if technology did rapidly change (nanomachines!) there would still be a business case for a Java-style language. Given how used to C syntaxes we are, it might end up looking like Java. Or Java might just be here to stay, for a long, long time.
Side note: a lot of "dead" languages nowadays are ones that were written before memory and processing power were abundant so they had a lot of (what we in the glorious future might call) arbitrary character limits.
sp(a,b); might have been sufficient back in the slow-old days, but we don't really consider character limits anymore, and so we can actually learn what a given line of code does by reading it.
SubmitPostOnHackerNews(commentID,messageText);
I think you nailed why I don't care for writing Java perfectly.
As for design patterns, the patterns that are really extensively used have more to do with overcoming the limitations of Java (or C++, C#, or whatever similar language) than with expressing anything profound.
Anyone that hates JEE, should spend some time having fun with CORBA or DCOM and see which one s/he likes best.
http://blog.insight.com/2010/10/cobol-still-in-action/
They write as much as they can outside COBOL. Those 5 million lines are for extending old programs or integrating new things into them. Some new programs are presumably written as well since... well, it's COBOL programmers writing them. ;)
Also, how much C was being written in UNIX 1.0 days outside of ports of same, exact software? :P
I think individual companies should define a language as "dead" based on the number of new people needed to maintain the systems. As the number approaches less than 5%(?) of your replacement hires, have you effectively "killed" the language? At the very least it is on life support, and a decision needs to be made about its future. (A grim analogy, I know).
I agree one should try to phase out something on life support. Gradually at the least.
So, it doesn't seem quite dead.
These projects have been in my queue for years because I kept chasing the "best" way to create Windows applications. I learned (and forgot) a lot of crap, but never actually made anything. Now I'm making stuff.
Pascal isn't dead! Native binaries produced (much less garbage overhead), fast compilation, kick-ass open source IDE and standard library, cross platform, free (as in freedom, as well as beer).
JOIN US.
LISP is widespread in education as Scheme, has lasting commercial deployments/companies with LispWorks and Franz Allegro, and new community with Clojure. However, one might treat them as separate languages given LISP 1.0 is very different from Common LISP which isn't Scheme or Clojure. So, it's up for debate but Scheme at 47 years old is probably justifiable due to academics. Racket is practical version with strong community. Chicken Scheme had one last I checked, too.
PL/1 (53 years old) is dead outside of legacy systems including mainframes and eComStation (OS/2). Yet, might be worth adding given that it has new code added to extend old systems like COBOL does. New compilers updates happen as well like below. Hard to say it's dead if it's still running companies, getting extended, and getting tooling updates. Just not popular.
http://www.iron-spring.com/readme_linux.html
Also, Burrough's MCP is still around under Unisys banner. It was first OS written in high-level, safer language: Burrough's ALGOL (56 years old). Became ESPOL (48yrs old) and NEWP (???). Unisys has a 2015 dated doc on NEWP. I think that means they converted most or all of the OS to it.
BASIC (52 yr old) was a language designed for beginners. Since it looked like pseudo-code, it was ridiculously easy to read and write. I got started on VB incidentally. Many spinoffs with wide deployments of commercial BASIC's for business, gaming, and education show it's far from dead. Not to mention 4GL's that were often BASIC-like. Could actually be one of the most widely, built-on languages ever made.
https://en.wikipedia.org/wiki/List_of_BASIC_dialects
So, there's more for your list.
EDIT to add BASIC in there.
“I don't know what the language of the year 2000 will look like, but I know it will be called Fortran.” —Tony Hoare, winner of the 1980 Turing Award, in 1982.
Given how things turned out, he might have better said:
"I don't know what the language of the future will be called, but I know it will look like C."
It is a very different language from the original Fortran.
I feel that the systems that change over time have the best chance of weathering it.
So, I think it's more fair to talk about LISP languages as an ongoing family but still a cheat to treat a modern one as original LISP. Probably should date it from creation of dialect or similar one.
Even if it hasn't changed in name, it may have changed in spirit. Some languages that promote themselves under very different names are substantially more similar than other cases where new language versions are dramatically different.
What 'essence' makes it the 'same language'? An interesting problem.
Algol used to be language you submitted things to the ACM in I think and is the systems programming language of the MCP, which my dad still programs in to this day!
It is interesting how many languages had an algol style syntax until C stole the show. I am not sure the world is better for it.
That's pretty neat. Everyone thinks Burroughs died but they just changed names. Make crazy money. System is quite dated, though, in features and interface. No denying that. ;)
"It is interesting how many languages had an algol style syntax until C stole the show. I am not sure the world is better for it."
I'm not sure on syntax. Decisions by top languages in terms of safety or reliability show ALGOL and Pascal families were right about those. You might like to look at Modula-3 and Component Pascal to see where things might have gone in a parallel universe.
https://en.wikipedia.org/wiki/Modula-3
http://blackboxframework.org/index.php?cID=why-program-in-co...
Note how power, yet simple, Component Pascal is by looking at the full language grammar in two pages of Wikipedia:
Well, on the one hand that's true. But on the other hand, a lot of the living languages have that too. BASIC is 52 years old, sure, but no 52-year-old BASIC program would even compile in a modern BASIC, and I mean, it's not even close, not like a couple keywords or some chars here or there, but the entire structure of the language is fundamentally different now.
By that standard: C is still recognizably the same. I'd suggest C++ is a different language before and after templates, which cuts it down to 27 years, and if you wait for the STL to be usable before you say they "took", less than that, but I imagine a lot of the early C++ would still compile or nearly so. Python has smoothly evolved and I can't point to any one feature that was a hard transition, but it is a fairly different language today than it was in the 1-1.5.2 era, but a lot of the 1.5.2 would still run OK. Javascript has actually been relatively stable as a language, coming out of the gate with rather a lot of stuff already built in. Java has also been pretty stable as a language. I don't know enough about Fortran or COBOL.
Lisp is an amusing case where a lot of old Lisp is probably reasonably close to parseable but probably doesn't run at all beyond the basics.
I fully acknowledge there's some subjectivity to the judgments here, but I think part of the 100-year-language idea is that code in the 100 years language should still be usable 100 years later, directly. By that age measure we're shorter on viable languages, though we still have some.
I worked on a large early C++ project and we had problems on the scale of a couple of years. Even if C++ wasn't changing, the compilers were.
You might argue it's changed the least, but only because all languages change a great deal.
I wouldn't state that so categorically:
foo(x)
{
return x+x;
}
or bar(x)
float x;
{
return x+x;
}
If you didn't live when that was C, I'm not sure you would recognize it as such. Certainly, I could claim it was B, C's precursor and get away with it with quite a few people. It doesn't look that different from the example at https://en.m.wikipedia.org/wiki/B_(programming_language)#Exa...: printn(n, b) {
extrn putchar;
auto a;
if (a = n / b)
printn(a, b); /* recursive */
putchar(n % b + '0');
}And even today's Visual Basic has gone a long way from the VB6 that most people remember VB by.
I think you would be hard-pressed to find any old Lisp code that a modern READ cannot turn into a list which could trivially be transformed into a valid s-expr in that dialect.
The reverse is much less true, since modern Lisp-like languages allow many more characters, are often case-independent, and often have standard "decorations" (e.g. &REST or #:optional).
Common Lisp is so kitchen-sinky that you'd be hard pressed to find old Lisp code that was then reasonably portable that will be outright hard to port to a modern CL implementation. Most of it will probably run as-is, or with a thin macro package doing mechanical translations.
Unportable code is unportable code. If it was so tied to e.g. Allegro that it wouldn't run in any other CL environment, that's hardly the language's fault.
However, really early Lisp stressed the "S" part, and rarely did anything strongly system-specific.
PROLOG - such a great idea, never really caught on. Yeah yeah I know minikanren and clojure core.logic but realize its gone from "The Japanese are using it to leap ahead of American AI research so we gotta catch up" in the late 80s to "whats that?" today.
To eliminate some battles over the definition of the word dead, how about "without too much effort you can get a paying job writing it". That works pretty well for spoken languages too.
That helps with Assembly. As a fraction of the pie its never been lower. As a device driver, embedded, firmware, compiler optimization (does that count?), and boot loader type of technology there's probably never in human history been more lines written per year. So its both dead and thriving by some definitions, but by my definition above its hardly dead.
I don't really get the appeal of basing a whole language on a backtracking algorithm. It always seemed to me that constraint solvers are better suited to a library implementation.
Although amstex and latex are healthy (and latex is about 40 years old) I would argue that very few indeed are writing in raw bare macro-free package-free tex, just bare totally raw tex. I'm sure it happens... rarely.
Another psuedo-dead is postscript. In the 80s there was a famous EE pushing the idea of sending your code and data to your postscript laserprinter as a batch frontend sorta and let the laserprinter interpret the postscript and do the calculations for your smith chart, not merely print your bitmap containing a smith chart or whatever. That idea of postscript as a general purpose application language, although infinitely cool, never went much of anywhere.
In that case Dennis Ritchie's K&R C is dead, if you don't count C11 as its successor.
If/when Python 2.7 dies out, Python's age can then be measured back to Python 3.
Etc.
IF we'll still be programming in 100 years, let alone using languages, instead of just telling an A.I. what to make. :)
We already don't use a lot of tech that we used to, because automated tools do it for us now. Assembly language is a relevant example right there.
I chose these languages because they occurred to me as being relatively old and relatively common, but I won't argue that there aren't any other languages that could be on the list.
I've read (not heard) it said that there may be more lines of COBOL in existence (probably meaning still running) than lines of any other language. Biz, insurance, gov't, IBM, etc. ...
FORTRAN and C are probably close seconds (relatively speaking).
The enterprise app developer writes Java for her day job, and spends her nights creating iPhone apps in Objective-C. Her apps connect with an API on the website she built using Ruby on Rails, and handles front-end interaction in JavaScript.
All four languages are syntactically similar, but each has vastly different application domains.
For all my personal projects I switched over to Python years ago because I just don't want to waste a single more minute dealing with basic stuff like strings in C.
I love the batteries-included mentality of Python because it lets me concentrate on implementing actual solutions to my problems instead of fighting against the build system or reliably converting strings into integers.
If there would be some kind of batteries-included version of C then I would certainly look into it again, but for now Python is just my preferred tool to get stuff done.
(yes, C++ is better in this regard than C, but it is still to cumbersome for my use case of rapidly playing around with new ideas).
At the moment I do a lot of image and audio processing via SciPy/matplotlib and I think that Rust is lacking in that department at the moment.
It's also easier to go up the stack to object oriented languages, particularly Java. The second chapter, first edition, of David Flanagan's Java in a Nutshell is still, in my opinion, the best intro to Java after having some experience with C.
I don't agree. What's the benefit in having to painstakingly write trivial string operations using string.h and manually allocated buffers? What's the benefit in learning the ins and outs of undefined behavior?
To force people to learn that making assumptions based on undefined behaviour is dangerous and that computers are not mind-readers.
And you force people to write buffer manipulation code so they realize how good people using other languages have it.
You can do that in a lot less time with, say, Array.sort in JavaScript. Explaining that signed overflow is undefined, and why it's undefined, is a whole lot of digression for little gain.
> And you force people to write buffer manipulation code so they realize how good people using other languages have it.
Seems like a lot of time to spend to make a point that would have been a lot more relevant in 1990 than in 2016.
I teach C, and every year I have a number of students nearly in tears, because somewhere in the huge program they accidentally malloced sizeof(T*) instead of sizeof(T), but of course that causes a crash 10 minutes later in a totally different piece of the code base.
My hope (it's not quite there yet, but getting closer) is that things like clang's sanitize modes will reach a point where any undefined behaviour immediately causes an abort. Then students can still figure out what they did wrong, but have a chance of finding the source of their bug.
#define ALLOC(n, type) (type)malloc(n sizeof(type))
which makes it harder to have those types of bugs, though not impossible.
In the beginning, the fear of getting some random Segmentation fault out of nowhere actually taught me more than any textbook, school or best practices blog could ever do. It also forced me to learn how to use debuggers :)
Also, many students previously did a course on Java, and clearly never really understood the basics, it's much easier in Java to play "keep tweaking and fixing the exceptions until it works, then don't touch it", particularly for introductory-level projects.
Really I wish I had access to it when I learned C.
It's hard to teach students not to over-rely on it, and trust everything it ever states. It seems best to first make them do some horrible debugging by themselves, and then move them onto valgrind late.
However if you deal with "student" problems I do not think this is the case. E.g. I taught a similar course to students and they appreciated that instead of
$ gcc -Wall -std=c99 foo.c
$ ./a.out
Segmentation Fault
they got something like $ gcc -Wall -std=c99 -g foo.c
$ ./a.out
...
==22907== Command: ./a.out
==22907==
==22907== Use of uninitialised value of size 8
==22907== at 0x4004F5: bar (foo.c:42)
==22907==
==22907== Invalid write of size 1
==22907== at 0x4004F5: bar (foo.c:42)
==22907== Address 0x0 is not stack'd, malloc'd or (recently) free'd
...
when e.g. writing to unallocated memory. I know for sure that there were often programs that were believed to be correct by students (and worse, often really worked, but not realiable), but had actually memory errors that were mostly reported by valgrind.I am not proposing to confront them with valgrind's details (I do not even know them), but explain that there is this tool that is a package in every popular Linux distro and ready to use to find these evil memory bugs (and they can be hard to hunt down if you are new to the language).
In particular I am interested in a false positive reported by Valgrind for a student exercise.
That's the cool part, algos don't necessarily require strings.
Realize he's proposing first years where you have to LARP that they don't even know what an if-then-else construct is, or what is a function, or what is a loop, or what is recursion, or what is the concept of a memory map, or what is the concept of data or memory locations having a type (like float, long int, etc), or what is the concept of a variable. In 2016 most of them probably know, but schools feel the need to pretend. Also non-majors wanting a code experience will need an intro.
This will make "real C programmers" very annoyed because OS code requires "real C skills" not a training wheels subset of C, but oh well. You can't really expect first year students to write OS code anyway.
One hidden advantage is it would take enormous effort for a noob to put a C program on the internet, so this protects them from themselves until they pick up things in later higher level classes along the lines of buffer overflow protection and GIGO concept and unit testing and so on. If you teach them what is a variable, using framework-of-the-week, they're just going to get themselves or an employer powned thinking they know what they're doing after one class.
If you know what you'd have to do in C to implement a certain feature, you can guess what a high-level language is probably doing under the hood when you use its canned features.
Only then should they learn C and its horrors.
I'm so glad it was in C , it allowed me to understand how the computer works better.
OO concepts were introduced after that, and the boilerplate code was explained. I'd done Basic, VB5, and what I'd call "C with iostreams" before college, and it felt like a fairly gentle exposure to classes and objects. Recursion took me longer to get a handle on, actually.
I was experimenting with Swift, trying to make it fit my rather performance/memory critical string processing needs. As it turns out, you can use C code from Swift about as easily as you can use Java code from another JVM language.
So I implemented a variant of the short string optimization in a few lines of C code. It's amazing how well C fits the bill as a lingua franca for code that does questionable things to bits and/or is meant to be used from other languages.
There's very little competition for C in that role.
However, when I don't need to hyper-optimised it is not my first choice due to being way behind other in languages in terms of package management and I'd rather not deal with pointers if I don't have to.
I wouldn't necessarily say that. At a glance, there are some questionable idioms: assignment inside a function argument (especially problematic since argument evaluation order is unspecified), old-style argument declaration, a custom Boolean type, less-than-descriptive variable naming, etc. I wouldn't let any of that pass code review today. :)
> The power of C is its stability over years, it remains basic, no advanced mechanism was introduced to the language, the code still simple to understand and maintain.
Not when you take the arcane undefined behavior rules into account. C semantics are anything but simple.
Maybe, but note that simplicity should be viewed in a relative sense.
I am curious as to which language you think has simpler semantics than C. For example, I have not found Python, Julia, MATLAB, C++, Verilog, or shell script simpler than C. Same goes for my initial explorations of Rust.
Even if one includes the arcane corners, the spec is < 200 pages (excluding the stdlib).
GHC Haskell with all extensions... euh, I don't know. Many extensions are either syntactic sugar or straightforward changes to the base language, sometimes even making it simpler. But I'm not confident about all of them, and I'm not sure how the semantics of some low-level libraries (ie for concurrency) work out.
I've written code in essentially just the standard subset and it's a pleasant language—there aren't any extensions that you absolutely must use in real projects. That said, people use lots of them anyhow because most make the language nicer without adding too much complexity.
Since the extensions aren't organized in a unified way and have to be split up (since they can generally be enabled or disabled independently), it's hard to figure out how complex they make the semantics of the language as a whole.
Isn't it also true that undefined behavior can stem from varying hardware/platform considerations? In particular, leaving some things judiciously undefined allows flexibility in implementations and thus can give good performance across a variety of platforms. Sure, one could force some precise semantics, but that might result in unnecessary "emulation" code on some platforms.
So at a programming language level, by having such emulation/fixed behavior, the semantics are simpler. But at a low level, the semantics are more complicated as the machine instructions may differ significantly, thus losing transparency. This is a concern in quite a few resource constrained applications.
For a simple example, see http://blog.llvm.org/2011/05/what-every-c-programmer-should-... and the section on oversized shift amounts.
Then, Modula-3 was the C++ alternative and its semantics are probably still easier than C due to simplicity plus well-specified.
C++ does not improve this.
I will go to my grave loving C, from that first day when I read() about it in unsigned char magazine as the high speed language of every malloc() exciting computer application, to the day when C++ took over and began to assert() its high falutin' notions of what a language should be.
I will goto my_grave loving C, from that day[0] ...Its like you can see the Latin roots of a lot of English, but reading it is like reading lorem ipsum. Same with C vs. JS with me.
(Those are my subjective feelings about those languages, not actual analysis of any real properties of those languages :) )
Yes, both I think. These are ways of thinking that simply don't seem to apply in JS or any other dynamically typed higher level language.
Also, just sort of the conventions of naming things, like malloc or memcpy or in the example of the article, all those crazily shortened abbreviations that may just be saving bits or the developers style, but make it very unreadable for me. I'm used to stuff like:
function getDataFromServer(){
var data = response
//blah blah etc
}
and it may just be a thing that you have to get used to with experience, but I can read and write Python, Ruby, JS, Clojure and other lisps, and have experience with C#, but something about C I just struggle with, and I wish that wasn't the case.Your example looks like completely valid C code to me (except for the lack of semi-colon).
"I can write C in any language."
And it's true. He could write beautiful C code in Perl, Java, Ruby, etc - whichever language the current project was using - when he needed to hack something (usually gathering data for business metrics).
Basically only using if/for/while and function/return constructs.
It was strange to open a Perl script and see "C" code, with single-letter variables (declared at the top), etc.
Other things I think make for good perl style:
* Never use unless, especially as the after-statement conditional and/or with a negation. (I once spent a whole day ripping my hair out to figure out that an unless with a negated clause that was itself ambiguously named did the exact opposite of what it seemed to. Think [...] unless not $unregulated;)
* Do use foreach wherever possible.
* Keep reference usage to where it's really needed.
* When in doubt, don't write new OOP code. (The benefit to the caller has to be much greater than the extra complexity in implementation.)
* Lists are the core data-structure and regex are first class construct.
* Avoid the use of implicit $_/@_.
* Avoid the use of explicit $_.
* Use map / grep / sort and similar in pipelines but don't nest too deep on a given line.
The real performance penalty is growing objects as you go. If you preallocate a list or vector of the appropriate length, then there typically isn't much difference.
That being said, you'll pry lapply(x, fun) from my cold dead hands (lapply(x, function (x) g(f(x)) is even better :) )
I want to see how he writes C style in Haskell.
It has been my experience that people who don't know or use the C stdlib end up unknowingly re-implementing stdlib functions over and over again.
At least if you use SSE2/FP/etc., you better ensure those FPU registers are saved and restored. But probably you don't want to do that in a IRQ handler! Save only SSE2 registers on an AVX system (higher 128 bits will be zeroed for currently executing usermode thread!) and receive "interesting" bug reports from the end users.
If you refer to a vm page that's not present... well, bad things might happen.
Etc.
Just disassemble/decompile some random firmware code... you wouldn't believe what one can find from those piles of err... binary dump.
If you know what you're doing (and you should) then C is the best tool for the job.
If we can get tools like Rust which have better memory safety guarantees while offering much of the same performance, then hell, why not? It's easy to see why just by looking at the hundreds of CVE's throughout the years, often caused by memory unsafe operations.
Not that I don't like C, but there's many better alternatives out there.
And this is coming from someone who stubbornly sticks to writing D in C-style, but knows what Rust brings to the table.
...and C is currently the best choice for systems like this because of reasons not primarily to do with the language.
Currently, if you suggest to use a language other than C you will be laughed out because the only available embedded guys are C based. Yes, momentum counts and C has massive momentum.
There are also issues such as toolchains and tooling, familiarity, community, and of course the massive existing set of libraries, codebases and knowledge.
Basically, C is 'good enough'. (although Rust is interesting and on the horizon, its a long way off yet).
Although technically a better language, C's shortcomings are greatly exaggerated, for example memory management. In general this is not an issue in bare metal embedded systems as you don't have a heap, everything is statically allocated by design. There are many flaws in the C language (as in every language), but in day-to-day use, they are very easy to manage.
So... don't believe the (bad) hype.
Social and economic factors that we C opponents say are why it remains and is often the pragmatic choice. These in no way show C language itself was well-designed, superior, etc. Just show how going mainstream can make things more practical. They did a great job on that part.
TBH, my ideal language for this job would probably be Rust, but that is just not a mature enough ecosystem currently.
Don't get me wrong, I would consider myself a C proponent currently, but I would love to see change in a Rust-like direction.
Despite you classing yourself as a C-opponent, I suspect we agree more than disagree.
Btw, what do you think of a reboot of Modula-2, Modula-3, or just Ada/SPARK? Your opinion on them would be interesting given your background. Closest thing to Modula's that's actively developed is Astrobe Oberon for embedded.
I started off with Turbo Pascal before graduating to Turbo C, so I do have a fondness for the Pascal family of languages. I also love type-safety.... TBH, I would prefer a hypothetical "fix" for the C language that improved type strictness/safety over "fixes" for resource/memory management issues which I consider should be bread and butter for any software engineer. So in that, I do not like large runtimes or garbage collection, more visibility to what the machine is really doing is needed. GC systems are also not predictable enough, deterministic runtime is absolutely essential to making reliable software.
I have poked my nose around Modula-2 in the past, but C took over for me personally. ADA I consider to be far to heavyweight for anything serious (and thats after being in a company that used it extensively in the defence world, tho I never had to touch it myself)
Currently Rust is my best hope for the future.... but C has survived well IMO.
For me a kind of escape path from C, back when I was into Turbo Pascal, was to move to Turbo C++. I only got to use Turbo C around one year before getting to learn about this new cool language called C++.
It allowed me to keep some of the Turbo Pascal safety around.
What are your approaches when using plain C, coming from "so I do have a fondness for the Pascal family of languages. I also love type-safety" ?
My solutions were:
- Use translation units as TP units, only exposing functions and struct accessors (macros if function calls were too expensive)
- Always make use of debug functions to validate pointers in debug builds (e.g. _malloc_dbg, _CrtIsValidPointer on Windows)
- make use of const as much as possible
- write my own wrappers around strncpy and friends
- compile warnings as errors
- if given the option, just use C++ instead and prefer library types to inherited C ones (string, array, references, RAII).
I'll be the first to admit that compatibility with an ecosystem, even if flawed, is important. (I work on web browsers, after all!) We can't change overnight, or even in two or three years. But we'll never get to a better future if we don't take the steps to start now.
Empirically, nobody knows what they're doing, if "knowing what you're doing" is defined as "writing large-scale C code without memory safety problems".
I hear a lot from C and C++ enthusiasts that there are lots of programmers out there who always write correct C and C++ code, and therefore we don't need new languages. But I've never found one of those programmers. Can you name one?
Basically, in day-to-day use, the flaws in the language are easily manageable. Resource (memory) management is a skill that should be a given.
Yes, there are well publicised failures in this regard, but consider the number of problems versus the actual number of lines of code written.
I think that's a pretty misleading metric when you take into account: (1) widely used codebases constantly increase in size constantly; (2) it only takes one exploitable mistake for an attacker to achieve remote code execution. One exploitable vulnerability per 10,000 lines means 1,200 remote code execution flaws in a codebase the size of Chromium.
I have worked with many who write large-scale C and C++ code with no undefined behavior. Is that what you meant?
I've never seen it. All large-scale C and C++ codebases I've ever seen, from large companies to small ones, have had memory safety/undefined behavior problems [1]. If "just hire better programmers" were a workable solution, surely one company out of {Google, Apple, Microsoft, Facebook} would have succeeded at that strategy by now.
It's very easy to write C and C++ code that looks like it's free of undefined behavior, but in every case I've seen they end up falling when attackers actively try to look for problems.
[1]: Maybe qmail is the one exception, though even that had a famous debate related to overflow.
Because I have, and it works incredibly well.
Of course, the caveat is that once you turn up the static analysis aggressiveness (assuming you use a good static analysis tool), you will need to put in plenty of assert(index < len), ownership annotations, and other such items in your code to satisfy the checks.
But once you do, it's really hard (probably not impossible, but really hard) to trigger undefined behavior without the static analysis tool catching it.
Because if the tool decides it can't prove there's no undefined behavior, it is configured to complain, and you adjust the code until it stops.
I'm not saying many teams do this, but I am disputing that no teams do this.
Btw, what utility tool are you licensing? What makes it irreplaceable? I know of only one in this field that I truly couldn't replace for compilers or static analysis. Even then, there's quite a few that handle the job well enough to not need it. So, I don't use it.
My hope is to some day open source our internal tool, but we have to wait until the OSS features we need catch up. Until then, we aren't willing to pay the high license fee to redistribute this utility freely.
I'm speaking a little cryptically because I'd rather not have this tied directly to any particular company (neither mine nor the one we license this code from). I'm not speaking on their behalves officially; only my own.
Coverity is actually used on browser engines, and it has not been able to stem the tide of exploitable security vulnerabilities. Sound static analysis is just too difficult on idiomatic C and C++: it's effectively impossible, as the language was just not designed for it.
If coverity isn't catching the bugs and they are undefined behavior bugs then coverity needs to be more aggressive.
But it probably doesn't support things like ownership annotations, and it probably gives up strict checking in order to avoid false positives.
The problem is developers. Developers are lazy. Most developers won't even turn on compiler warnings, never mind using the sanitizers.
So tool makers create sub-par tools to cater to them. Fewer false warnings means more customers, even if it also means fewer security holes.
It's why we use an in house tool and crank up the checks to 11.
If you watch Herb Sutter's talk at CppCon 2015, at a given point he asks the audience how many know and use such tools.
It is one of the most important C++ conferences, usually attended by the most savvy C++ developers in the world, the amount of the audience saying that they do use such tools was ruffly 1%!
1% shows how much the majority of C and C++ developers, or their employers, care about writing proper safe code in those languages.
The only way out is moving to programming languages whose safety must be explicitly turned off, and not having to be explicitly turned on, because most won't bother taking the effort to turning it on.
What I'm disputing is that no teams write good C or C++ code.
In fact, the 1% who raised their hands proves my point. It isn't 0%.
That's all I'm saying. Don't smear our names with the "all C and C++ developers write code with exploitable undefined behavior bugs in it" when you mean "most C and C++ developers write code with exploitable undefined behavior bugs in it".
Once upon a time I gave C++ class to first year students at the university where I took my degree. Worked with C++ at some well known companies and research institutions.
Still, I won't say I never write exploitable undefined behaviour free code in C++, let alone C. Because I cannot control the code that gets used by third party libraries, written by team members or even having the whole UB use cases on my head.
If you rely on binary dependencies which have quality problems, then u can't help you there. But that could be an attack vector in any language.
And if you are worried about the operating system itself, then there really is no easy way around it unless you want to run a unikernel for everything.
And even then you may hit a CPU microcode bug it hardware bug...
I hope to never own a microwave oven with a large scale codebase. Also my basement dehumidifier. And my waffle iron. And my clothes washer. And my digital dial caliper in my workroom.
There's a surprising amount of money in "you are now a timer" and "you are now a thermostat" and "you are now a thermometer" and very close analogies.
You'll definitely use or own something that has a somewhat large codebase.
That is both reliability and return on investment. :)
So, when we use evidence instead of feelings, what you said is a myth that's been debunked repeatedly in many ways for decades. And, yet, people repeat it. No, C use usually results in problems that safer, systems languages before and after it had less or none of. Despite professionals using it. The solid code is always an outlier.
Most amusing thing is Thompson and Ritchie, with help from Pike, later designed what they thought was perfect language with perfect set of features. The result, Go, was basically like Algol subsets that preceded C mixed with Pascal developed around same time. But, C compiled and ran on a PDP-11 fast. So, it's the best. ;)
And I am not claiming that C is the best tool for the job because of the language.... its because of the 'environmental' factors, human resources, community, momentum, codebases, portability, etc.
I whole-heartedly agree that there are better languages out there, but the fact remains that the flaws in C are easily managed.
It would also be interesting to produce a study of the use of C specifically in embedded systems where the style of code is very much different than large desktop systems (i.e. much less heap usage and dynamic memory allocation for example).
I agreed with you on that in another comment. Yep. It's also why NASA often uses it. The tooling covers dark corners pretty well these days.
"It would also be interesting to produce a study of the use of C specifically in embedded systems where the style of code is very much different than large desktop systems (i.e. much less heap usage and dynamic memory allocation for example)."
I'd love to replicate the old studies on modern languages with modern tooling for both systems programming and the embedded subsets like MISRA. We'd definitely learn some stuff from that. Further, I'd like to see specific metrics like in Ada/SPARK/CbyC example below on where defects were introduced or corrected with each technique and phase of lifecycle. Would tell us how low-level features, subset rules, and tooling interact with accurate assessment of how much problems they pose for real instead of in theory.
http://www.sis.pitt.edu/jjoshi/Devsec/CorrectnessByConstruct...
Modern embedded C programming has evolved significantly in the right direction since studies were done and so I would love to see someone spend the time looking at 'modern' embedded C codebases.
Static analysis is now widespread and not theoretical, coding standards now take security seriously (tho can be outdated). Drawbacks to certain techniques have been surfaced and recognised. Tooling is much better, portability is recognised as a good-thing, pointer usage is now minimised when possible and contained to areas where they are appropriate. Casting is frowned upon, macro-magic is frowned upon. 'Clever' code is frowned upon.
Basically, I would think that certainly in the embedded domain, standards are now such that the story would now be significantly different.
Dont trust just one.
I was hoping for something new.
I'll look into those.
Saturn http://saturn.stanford.edu/pages/overviewindex.html
CSolve http://goto.ucsd.edu/csolve/
Calysto http://www.domagoj-babic.com/index.php/ResearchProjects/Caly...
Most academics are instead making compilers that translate C code into something mostly or totally safe while pushing the performance hit downward. Here's two of the top for you to try on various codes (or improve):
C was my introduction to "real" programming -- it forced me to actually learn memory management, pointers, etc. Funny thing, I only took one C course while I was in college. By the time I started college, Java was the new hotness, and I was in the first incoming freshman class to get Java instead of Pascal in our introductory programming course. I took an immediate disliking to Java back then (and still don't like it), so naturally it's the language I have to use at work :O
The underlying instructions generated by the compilers are simple to follow. Reasoning about what will be generated is an easy enough task (so long as optimization is turned off).
http://www.netzmafia.de/skripten/unix/chist.html -- Dennis M. Ritchie
Seriously enough, Lua adds all those scripting high-level aspects that are missing from C. I know it's another language but its interplay with C gives strength to both of them. A good alternative of the C + Lua paradigm is of course Python.
This obviously gives it a big leg up for employer demand, etc.
Of course there's a central data store. But that's okay.
https://www.cs.rit.edu/~ats/books/ooc.pdf
Many think C++ with its benefits and problems are relevant to OOP in C but not entirely. That's because they think C++ was about adding OOP to C. It wasn't. Stroustrup used safe, OOP languages like Simula that he wanted more of. He intended to leverage C's popularity and tooling but transform it into something with benefits of other languages. So, the result is C-like but not quite C and complex.
Just doing OOP in C, on other hand, is much easier and cleaner problem to solve. ;)
The C language is still very popular