
Why I’m Using C - mmoez
https://medium.com/bytegames/why-im-using-c-2f3c64ffd234
======
strategarius
"Reliability" \- in a language with manual resource management and unsafe
parallelism model? Really? BTW never heard of modern games written in C.
Mainstream game engines (UE, Godot, Unity...) are written in C++ and C# and
cover all major platforms and consoles. "Performance" \- Rust is probably more
performant when it comes to code, and definitely more performant when it comes
to development time. "Simplicity" \- primitivism is a closer definition.

~~~
dragonsh
Rust is not close to hardware as C is, so if need to do anything with hardware
Rust still relies on majority of the code written in C. Performance wise today
C is still faster than Rust in general.

Rust is still a decade or more away from anything serious like C. Majority of
the functional Rust libraries today depend on underlying C libraries.

Rust may try to replace C++ but replacing C is far away dream.

Let's wait when Mozilla (origin and major supporter for Rust language) can
release Firefox in Rust, until than it's still a popular experiment in systems
programming area.

Rust does not run any critical component like Linux Kernel today, when it will
be able to do it than it can be considered as real systems programming
language challenger to C. Right now most of it's safety guarantees are not
really battle tested like C.

~~~
strategarius
"Rust does not run any critical component like Linux Kernel..." \- and the
only reason why it is not happening (provided that C and Rust have perfect
interoperability, more and more C/C++ developers get familiar with Rust) is
the fact that Linus Torvalds convinced by voices from Ethernet socket not to
use anything but C. I can't wait for him to retire so that Linux kernel devs
could pick up more modern toolset

~~~
adwn
As much as I love Rust: As long as Rust doesn't support all platforms which
the Linux kernel supports, it really is a no-go for kernel code in general.

~~~
steveklabnik
"in general" is a bit strong; the maintainers have said:

> I spoke with Greg Kroah-Hartman, and he said he'd be willing to accept a
> framework in the kernel for writing drivers in Rust, as long as 1) for now
> it wasn't enabled by default (even if you did "make allyesconfig") so that
> people don't _need_ Rust to build the kernel, and 2) it shows real benefits
> beyond writing C, such as safe wrappers for kernel APIs.

[https://lwn.net/Articles/797828/](https://lwn.net/Articles/797828/)

~~~
adwn
That's why I wrote "in general": It's not yet suitable for most kernel code,
just for some specific cases (i.e., optional drivers).

Hmm, maybe I should have written "...for _general_ kernel code" or "...for
_most_ kernel code", that would have been clearer.

~~~
steveklabnik
Ah yeah, I see that now... words are hard, I think you can read this both
ways. Sorry about that!

------
pritovido
I use C(as a backend) because I understand it.

In reality I use anything that gets the job done faster. That usually means
prototyping in C++,lisp, python, swift, java, perl, lua.

After I have the prototype I code it automatically with C, or minimal C++ and
my own DSLs, done in Lisp controlling C, C++ code generation.

I have reinvented the wheel a lot. Someone told me you are not going to be
smarter than a compiler, but having read several of them, they are so dumb,
and they have to be because they are generic.

E.G In a project I was using std::vector and predicted the expected
performance of the whole program by O notation and "on the park" calculation
needs as X.

When I completed the program, it was X/1000\. Fair enough I made some stupid
mistake...in the end I got X/100 performance and could not optimize farther.

I got so frustrated so I started replacing components to see if numbers
improved. Replacing std::vector by a c vector made the program X/1.4!!

So I started studying std::vector implementation and it was a template of a
template of a template... I could not wrap my head around such a mess.

My implementation was done in lisp with proper macros and was way simpler and
efficient and generated c code, that was so easy (although tedious) to
understand.

~~~
wuschel
Could you perhaps elaborate on the LISP/DSL approach to programming that leads
to efficent and safe C code?

Thanks.

~~~
taylodl
I second this request!

~~~
wuschel
A quick Google search gave quite a bit of results e.g. C-Mera [1].

[1] [https://github.com/kiselgra/c-mera](https://github.com/kiselgra/c-mera)

------
systems
Ok,

I think since none of his reasons include I am doing system programming

I will debunk

Reliability: C is not the only language with a reliable ecosystem, and what
should matter most is the reliability of the program, not the tools made to
create the program, so in this regard, I think Rust, OCaml, C#, Java are all
as reliable, and I would argue it is easier to write more predictable or
reliable programs in them

Performance: Yes sure C wins almost every performance benchmark, but Rust is
very Fast and Ocaml is also very fast so unless you are working on system
programming stuff, I think you have better options that are more reliable and
predictable

Simplicity: Here I would like to contrast simplicity of the tool vs simplicity
of the product, complexity does not go away, complexity is abstracted, simple
tool = complex product or process, complex tools on the other hand may allow
you to create simpler tools and processes, if you use simple tools you will
transfer complexity to your products, which I don't think is necessarily a
good thing

~~~
jkoudys
Rust will frequently build code that will run in a comparable number of
cycles, but can often run even faster as soon as you introduce concurrency.
Safety isn't just some crutch to lean on instead of simply being really,
really careful in C. Concurrent apps need a lot of guarantees for memory
safety, and it takes a lot of mental energy to figure out how safe you really
are. C devs often go overboard and do more than is necessary as a result.

------
billfruit
While it is true that C perfectly matches the hardware, it imperfectly matches
the rich software abstractions which are needed for moderate and large sized
software. The lack of namespaces and sane object creation, destruction
semantics etc, makes programming tedious.

A large proportion of code in many large C programs go into recreating
imperfectly the features that are by default provided by richer programming
systems. And that repeats for every large program you do. It quickly becomes
boring and unenlightening, to recreate an exception handling mechanism or data
structure implementation for the nth time.

Why would anyone not prefer not having to focus on the mere infrastructure,
and rather direct directions on the interesting problems to be solved.

Another thing is that large C code bases tend to become ensconced in layers of
preprocessor macros, which I think is a hack-y way of doing things.

------
jkoudys
You'll build to almost the same number of raw CPU cycles executed for the
code, but probably build a better-performing game in a language with
safer/simpler concurrency/parallelism. Ever since futures (concurrency) has
stabilised, rust's my first choice on this. Pretty much all of his points not
related to the sheer age of C apply; you can even get the 0-byte-overhead
webassembly if you go no-std, though I seldom forego something so useful
that's smaller than the loading-screen background.

------
johnklos
It seems like many of the responses to this article are from Rust and other
language fans (but mostly Rust). I think many people are reading what they
want instead of what the author was trying to convey:

"This is the most important and only real non-negotiable requirement for me;
the reliability and portability of the toolchain and the access it provides to
system and device interfaces."

Rust isn't exactly reliable. Try to build Rust itself. There are all sorts of
issues with resource consumption and parallelism, and it takes more CPU and
memory than compiling an entire OS.

Rust's portability is strongly discouraged by the resources it requires. Many
platforms REQUIRE cross-compilation because they don't have enough memory, and
this makes it hard to say it's easily portable.

If you're a fan, you're easily going to overlook this. You probably don't care
that more than half the world doesn't have computers which have the resources
to run Rust. That's fine. You also say that people shouldn't be concerned with
compiling their own stuff. That's fine, too. But there are people who like to
create projects and write software that's as accessible as possible to most
people, not just to some people and available to many others just as
downloadable binaries.

If you're not the kind of person who wants a free and open software ecosystem
where everyone can participate, not just those with the resources to buy
fancy, powerful, multigigabyte, multigigahertz, multicore 64 bit CPUs, then
Rust is fine for you. If you you care about accessibility to as many people as
possible, perhaps you'd come to the same conclusions as the author.

~~~
loup-vaillant
It seems you are working on a different set of constraints than the author's.
The author was talking about making games. Those are generally proprietary,
and even the free one almost always have binary distributions. Rust _itself_
likely have a binary package for your development platform of choice.

Likewise, cross compilation is likely not a problem. You don't develop _on_
the PS4 or Switch, you develop _for_ them. Sure, in practice, cross
compilation in C and C++ is indeed a problem. I'm wondering to this day how
that's even a topic. A compiler is just a goddamn translator, the target
platform should naturally be independent from the source platform. Worst case,
you need to recompile the standard library for the new platform. (I suspect
this is related to the bewildering difficulty of linking libc statically.)

You do have a point, but it's much broader and much stronger than choosing C
over Rust. We spend heaps and heaps of code solving problems that could be
avoided in the first place. Niklaus Wirth's Oberon operating system required
less than 10,000 lines of code, and now we need like 200 million lines?! No
way we now have 20,000 times the functionality, so we can guess that current
computing systems are at least 100 times too big (that is, comprised of over
99% accidental complexity, Brooks be damned).

I sometimes feel the only way to make software truly Free and Accessible
(meaning, people have the right _and_ the means _and_ the ability to use &
modify their software), is to remake everything from scratch, with the benefit
of hindsight.

------
rvz
> Why on earth would someone would pick C to start a new project in 2020?

Please ask yourself this before writing any code (For a cross-platform game).

By just reading this, I thought to myself if I were to write a cross-platform
game in 2020, Is C necessary to accomplish this? Perhaps anything C can do,
surely Rust can do it safer and arguably better.

~~~
timw4mail
The biggest advantage C has over Rust is the sheer breadth of platforms. As a
developer, I would always prefer Rust over C, if possible, but sometimes C is
more realistic.

In most cases, C would only be more practical on obscure or outdated hardware,
though.

~~~
worldsayshi
I fear that we are slowly moving towards a situation where our underlying
technology stack is written in languages that a diminishing number of people
have seniority in.

96% of the Linux kernel is written in C
([https://github.com/torvalds/linux](https://github.com/torvalds/linux)).

~~~
mroche
The GitHub counters are not always accurate. 97.3% (if going by C (imp+header)
and Assembly) of the kernel is written in C, with the rest being written in
Assembly. Everything else is config files, scripts, tests, or docs. GitHub
reports C++ and Objective-C; those are just .h header files.

Update: Got to my system so I could actually look at available files
accurately:

    
    
      C Implementation (.c): 28269
      C Header (.h): 20250
      Asm (.S): 1323
    

Edits: Update section and removing "100% in C" and "5 sources files of
assembly"

~~~
clarry
Eh, find -iname '*.s' in kernel source tree finds more than a thousand files
and half a million lines in them.

~~~
mroche
I wasn't at my system when I wrote that and just checked (5 is way off the
mark there). Should have followed my own advice and not used GitHub's counters
:P

The counter reports 1.2%, but if you click on that to show Assembly files it
only reported 5 code results (it's not actually showing all Assembly, so you
then have to click on "Unix Assembly" on the side).

------
jcpst
“Why I’m using medium to write this article.”

I was curious about this, but medium wants me to create an account to read it.
Oh well.

~~~
llarsson
Block javascript on medium. Makes it much better, no nagging, no
limitations... sometimes you miss an image or two, but the text is there.

~~~
padthai
For me this does not work anymore. What I do is redirecting the domain to the
Wayback Machine.

------
guggle
"But It’s not just about running fast, battery life matters as-well. Fewer
cycles means less battery consumption which is a major win if you ask me. As
long as I can help it, I’ll do my best to avoid draining a user’s battery in
five minutes."

I was thinking about languages in terms of ecology. I'm a Python fan and while
its lack of performance never bit me in the real world, how many Joules would
be saved if my apps were written in another language ? I'd love to see a
study/comparison based on real apps (not algos implementations).

~~~
turbinerneiter
Here you go: [https://greenlab.di.uminho.pt/wp-
content/uploads/2017/09/pap...](https://greenlab.di.uminho.pt/wp-
content/uploads/2017/09/paperSLE.pdf)

~~~
guggle
Yes, thank you, I knew this study. I wonder how real-world apps would change
(or not) the conclusions.

------
glouwbug
The great benefit to C is that it doesn't change. You won't feel tempted to
rewrite your entire project 3 years later with the newest features

------
IshKebab
I wish the myth that C is simple would die. It has all sorts of complex nooks
and crannies. Even some basic things like specifying types are quite insane
(e.g. for function pointers).

~~~
loup-vaillant
C gives you an initial illusion of simplicity, and being close to the
hardware.

Then you learn about Undefined Behaviour.

~~~
clarry
The language would be _more_ complex if it tried to specify all behavior. UB
allows it to be simpler.

Do not confuse simple with easy.

~~~
loup-vaillant
I disagree. Much UB makes the language less orthogonal, and ultimately makes
the specification _longer_. And more complex.

Classic example of illusion of simplicity: signed integer overflow. Going
outside the range? Undefined. Left shifting a negative integer? undefined. You
can't just assume 2's complement, you have to be aware of the Nasal Demons
compilers are becoming increasingly apt at summoning.

Another one: out of bounds array index is undefined, _even if there was
something of the right type there_ :

    
    
      #include <stdio.h>
      #include <stdint.h>
    
      typedef struct {
          uint64_t a[8];
      } blk;
    
      int main()
      {
          blk b[2];
          for (size_t i = 0; i < 16; i++) {
              b[0].a[i] = i;
          }
          printf("normal  : %lu\n", b[1].a[2]);
          printf("overflow: %lu\n", b[0].a[10]); // undefined
    
          return 0;
      }
    

Depending on optimisations and compilers, you won't get the same result every
time, and all sanitizers warn you about the UB. Conclusion: you can't assume a
flat memory model, even on modern X86 in 32 or 64 bit mode. There are
exceptions, depending on how you access memory, through which pointer. Again,
your language specs just got longer for not defining what happens outside the
bounds.

\---

Undefined behaviour simplified _one_ thing: the compilers themselves. At
least, until they got the idea to use UB for optimisation, and started to
summon the Nasal Demons as a result.

~~~
clarry
> Classic example of illusion of simplicity: signed integer overflow. Going
> outside the range? Undefined. Left shifting a negative integer? undefined.
> You can't just assume 2's complement, you have to be aware of the Nasal
> Demons compilers are becoming increasingly apt at summoning.

I don't see this as an example of illusion of simplicity. On the contrary.
Specifying exactly what must happen on integer overflow or left shift is
almost always going to require more than saying "the behavior is undefined."
Especially so if you try to keep it portable and allow different behaviors
that are natural for different systems. And it probably won't help you if
you're trying to write portable code, because now you need to worry about all
the _defined behavior that might not be what you want._

 _If you want portable code, then you shouldn 't be able to assume a specific
behavior, and if you want a language standard that enables the language to
perform well across dislike platforms, you can't dictate specific behavior._

If you don't care about portability, you're free to enter a contract between
you and your platform & compiler. For example, use -fwrapv. The standard
doesn't forbid such a thing. By keeping things simple and leaving them
undefined, it explicitly enables you to do things like this without violating
what's defined in the standard.

> Another one: out of bounds array index is undefined, even if there was
> something of the right type there:

That's a very specific scenario. In a lot of cases, there are arrays whose
indexes are not right there, not constants (would require range analysis), or
array size is not known (but maybe could be inferred). So the standard would
have to become more complex in order to specify that something specific must
happen in the special case that you're indexing into an array of known size in
scope, with a constant index. By simply making out of bounds access undefined,
they cover _all cases_ of array access in one short sentence.

Luckily, again, since the standard doesn't require any specific behavior, your
friendly implementation is free to invent its own specific behavior, for
example issue a diagnostic and return an error code because it saw that you
were indexing out of bounds.

> Again, your language specs just got longer for not defining what happens
> outside the bounds.

Why don't you show how to make the spec shorter by defining exactly what
happens in this specific case? Remember that the spec still has to cover other
cases, so you can't just delete all the text. You have to add a new case! Post
a diff.

~~~
loup-vaillant
_Integers represent the binary field of integers modulo 2^b, where b is the
width of the integer. For signed integers, any value v >= 2^(b-1) is
interpreted as being v-2^b instead._

That's how you specify "exactly what must happen on integer overflow". You
thought I would have to take every undefined special case one by one and
define them? That's naïve.

A similar argument can be made for pointers: _pointers are integers that
represent memory addresses. Dereferencing a pointer to an allocated region
gives you the value stored in that region (insert casts, uninitialised values,
trap representations etc here). Dereferencing a pointer to a region that is
not currently allocated is undefined._

And voilà, we no longer care _how_ a pointer was constructed then
dereferenced, we only care about the address, and whether it pointed to an
allocated region (and initialised with a compatible type etc, though that part
could also be simplified).

> _That 's a very specific scenario._

I'm currently reporting a bug in the Libsodium cryptographic library because
its Scrypt implementation (password hash by Colin Percival) has precisely this
bug. My guess is that Colin was a _little_ too clever there, and treated C as
a lower level language than it actually is.

A very specific scenario that may be, but it's a scenario we do encounter in
real life.

~~~
clarry
> That's how you specify "exactly what must happen on integer overflow".

So yes, like I said, you can _force_ a particular behavior, and throw out any
system for which that doesn't come naturally - you just made the language more
complex for them. And no, that is not simpler than "the behavior is
undefined", just different (and more imposing).

> And voilà, we no longer care how a pointer was constructed then
> dereferenced, we only care about the address, and whether it pointed to an
> allocated region (and initialised with a compatible type etc, though that
> part could also be simplified).

Eh. You did nothing about undefined behavior. It's still there.

> A very specific scenario that may be, but it's a scenario we do encounter in
> real life.

So what was your proposal that doesn't make the language more complex? Because
above, you just gave us undefined behavior, which is our starting square.

~~~
loup-vaillant
> _So yes, like I said, you can force a particular behavior, and throw out any
> system for which that doesn 't come naturally_

Find me _one_ system in current use (2020) that isn't 2's complement.

> _you just made the language more complex for them._

Ah, but I was never talking about implementation complexity. I was talking
about _specification_ complexity. Imposing 2's complement makes the
specification simpler. No special case, no boundary. Just a binary field.
Undefined behaviour draws such a boundary. An extra detail to specify and
remember. Some thing that reminds you you're not _quite_ doing modular
arithmetic.

> _Eh. You did nothing about undefined behavior. It 's still there._

I did. There's less of it. I've filled the bug, here's what's this about:
[https://github.com/jedisct1/libsodium/issues/937](https://github.com/jedisct1/libsodium/issues/937)

Here's the relevant quote from annex J of the (heavy, I have printed it) C99
specifications:

 _Addition or subtraction of a pointer into, or just beyond, an array object
and an integer type produces a result that does not point into, or just
beyond, the same array object. (6.5.6)_

That's what caused the bug: we were taking a pointer from an array, then used
it to overflow past it. It didn't matter that we could access the memory
there. What mattered is that we locally overflew that array. Had we computed
the pointer by first working with the _outer_ array, then pointed to the right
element, we'd have the same pointer, except this time it wouldn't be
undefined.

Bonus note: you don't even have to dereference the pointer, computing its
value is enough to trigger undefined behaviour.

Here is some more undefined behaviour I have removed (it's subtle, relatively
few programmers know this):

 _Pointers that do not point into, or just beyond, the same array object are
subtracted. (6.5.6)_

There go flat memory models. Though to be honest, even segmented memory models
could define that. Just make the subtraction already, it doesn't have to
_mean_ anything. Make it unspecified or implementation defined at least.

 _Pointers that do not point to the same aggregate or union (nor just beyond
the same array object) are compared using relational operators (6.5.8)_

That's the reason we can't implement memmove() portably and efficiently. And
depending which tool you ask, even converting the pointers to intptr_t first
isn't enough. Real world example here:
[https://github.com/jedisct1/libsodium/commit/e7e378fad116c18...](https://github.com/jedisct1/libsodium/commit/e7e378fad116c18c78274e9b268acbd8a653268b)

\---

If you haven't already, go read the annex J from the C standard. Ponder the
fact that compilers, unless you specifically ask not to (-fwrapv), will
exploit every single one, _even on platform that could define some reasonable
behaviour_ (2's complement machines). It may hint at how _hostile_ C is to
programmers who care about correctness.

Believe me, I know. I wrote a whole Crypto library[1], and that's one of the
_easiest_ things to get right, where C is concerned. I mean, the crypto itself
is hard, but the total lack of dependency makes it pathologically easy to
write in a portable way. Yet C still makes it hard.

[1] [https://monocypher.org](https://monocypher.org)

~~~
beefhash
> Find me one system in current use (2020) that isn't 2's complement.

Fortunately, C2x will stop with the meme assumption that two's complement
hasn't taken over the world (see draft N2479). It will not, however, specify
signed integer overflow, which remains UB. :^)

~~~
loup-vaillant
Compiler writers are too hooked on loop optimisations now to give up on
undefined signed overflow. I'm afraid the only clean fix is to augment the
language with an _actual_ `for` loop, with an immutable loop index and well
defined start and finish values. Stuff like:

    
    
      for (size_t i : 0..10)     {} // Will go from 0 to 9 included.
      for (size_t i : 10..0, -1) {} // Will go from 10 to 1 included...
                                    // ...or maybe from 9 to 0 included?
                                    // Not sure which is best.

------
cartoonfoxes
Could we have a discussion about C without making it about Rust? The author
doesn't mention Rust once.

------
shamas
That does give some food for thought. Of all the new language features, the
elements I really need —functors, asynchronous syntactical sugar, and static
null analysis— don't require much of the bloat found in many modern languages.

------
SteveSmith16384
I assume that since he's writing a game, he's using some kind of
library/engine/framework, but doesn't specify which one. This would affect his
arguments for reliability (is the framework available on all these platforms?)
and simplicity (how simple is the framework?).

Maybe he's only writing an ascii game though.

~~~
tobyhinloopen
SDL is a common one, and is really easy to use

------
eatonphil
Random note: every few years I update a list [0] of popular programming
subreddits (by subscriber count) on the /r/programming wiki. Over the last two
years, C increased in popularity overtaking Ruby. And C++ increased in
popularity overtaking PHP.

Rust, TypeScript, and Dart made big gains as might be expected. Swift didn't
really move anywhere.

The biggest surprise for me were how much the interest in C and C++ continues
to grow relative to other high-level languages (that probably also have
greater number of professional users).

[0]
[https://www.reddit.com/r/programming/wiki/faq?v=0692c0d1-617...](https://www.reddit.com/r/programming/wiki/faq?v=0692c0d1-6174-11ea-98bc-0e55b58028a7&v2=1063c806-621f-11ea-8159-0e437a1ed589)

------
exabrial
> Languages, especially dynamic ones and their runtime environments come and
> go like fashion.

Sage advice.

~~~
tonyedgecombe
Hardly, Ruby is 25 years old, Python is 30, Javascript is 24.

~~~
eddieh
Well, Ruby is waning, Python is surging, and JavaScript is peaking. How will
this look in 5 years? How about 10 years?

Would you say PHP is in fashion? How about Perl or Tcl?

~~~
falcolas
Who cares about fashion? In 15 years Ruby, Python, JavaScript, Perl, TCL
(particularly for building simplistic but effective GUIs), and PHP will all
not only be usable, but actively used.

~~~
eddieh
This thread is about fashion.

Did you read what the OP quoted? Here it is:

> Languages, especially dynamic ones and their runtime environments come and
> go like fashion.

~~~
SteveSmith16384
He's talking about languages coming on going. "Languages, especially dynamic
ones and their runtime environments come and go like fashion. __When your
target platform suddenly gets deprecated from the runtime you’re relying on,
well then you’re just fucked and out of luck. __"

------
mmoez
The article without Medium paywall: [https://hownot2code.com/2020/03/13/why-
im-using-c/](https://hownot2code.com/2020/03/13/why-im-using-c/)

------
bsenftner
> For example; I doubt I’ll ever be reaching for C when writing a web service
> simply because the ecosystem around that domain isn’t great and I’m not
> itching to write my http framework at this time.

C has everything, including several top quality http frameworks. I use
[https://github.com/corvusoft/restbed](https://github.com/corvusoft/restbed)
and find it more reliable, more performant, and "better" in all respects than
the php, js, node, and whatever frameworks I've been forced to learn.

~~~
koffiezet
I have programmed in C for a long time (for embedded before everything became
ARM+Linux), and unless you have technical reasons to use C for a new project,
I would skip it. I like tinkering with the low-levelness of C, but what
applications really need that these days unless you're working with
hardware/os level stuff?

There's also so much FUD about performance, but reality is that without
numbers, you'll never know. Certainly for game development, unless you're
working on a cutting-edge game engine, there's little reason to focus on
performance first, and even then - most popular modern game engines offer
interpreted paths for game logic.

Fear of garbage collectors is also bullshit in most cases. Many don't realise
a simple call to free or malloc (or new/delete in C++) can result in just as
much unpredictable hick-ups, which is why many games engines use specially
tuned memory managers, some even specifically including garbage collectors
(see the Unreal Engine for example).

Certainly in game development, flexibility to tune game mechanics is far more
important to make a good game than performance, and creating such flexibility
in a C application is a lot more complex/more work than in a higher-level
language, and you'll end up building very high walls you really don't want to
tear down and start over with.

~~~
bsenftner
The thing I find interesting about C is that everything and anything done in
other languages can be done in C; after all, how does that language implement
feature X? In some low level manner, and that is where C shines. C is not just
the language, it is the entire ecosystem of all available source code written
in C - compilers, browsers, you name it, it is there. Working in C is as much
research and integration as one wants, with the results being any flavor of
programming style you want - with all the foundation bits under your complete
control. Plus the community of pure C developers is people that have been
working in it for decades, with more practical programming wisdom than you'll
find in shops with teams of high level developers releasing modern
applications. The C teams release them too, but theirs is exponentially higher
performance in exponentially smaller foot prints. Lots of software shops
appear to be more into empire creation than quality software, but that's a
result of decades of software industry propaganda too.

~~~
koffiezet
> The thing I find interesting about C is that everything and anything done in
> other languages can be done in C

With emphasis on "can". Not that you should. This is exactly what I mean, in
many cases it's interesting for an intellectual exercise, but I would avoid it
for new projects unless I really can't.

------
jjgreen
C, besides its intrinsic beauty, does not fill you with the urge to tell
others to pipe curl output into their shell; that's a win for me.

------
leecarraher
i use c in scientific computing for small processor intensive routines that
can leverage openmp's straightforward parallelism.

~~~
vkoskiv
Have you considered using `phtreads`? It's part of the POSIX standard, and
it's less cumbersome to use.

------
SteveSmith16384
I agree with all his arguments, as long as I'm only writing HelloWorld.c :o

------
tobyhinloopen
I like working with C. It’s simple and transparent. I wish I could use it
more.

------
32gbsd
Nothing new really

~~~
jonnypotty
You would have been better off writting that in rust

