Hacker News new | ask | show | jobs
by notquiteright 1012 days ago
I knew these were all ”I don’t know” edit: but yes, deceptive phrasing by the quiz author. If you don’t know that, then yeah, you’re probably not a great C programmer. Adjust your mental model: C is meant to be useful on a very wide variety of platforms, including ones that don’t follow the conventions (ASCII character table, size of byte, alignment requirements, etc.) of the most common platforms.

Even including knowledge of what is IB and UB, C is still simpler than most languages in common use these days.

5 comments

If “the standard doesn’t define it” is a reason for “I don’t knows then all of rust is “I don’t know”. Seems silly.
Rust still behaves in a consistent way, anything undefined by the C standard can and often will change between platforms and compilers and optimisation levels
Undefined per se is not a bad thing. It means "compiler can make choices based on certain assumptions in the name of performance". The problem with c is that you must have a comprehensive dictionary in your brain with tons of corner cases to know what is or is not undefined in any given compiler setting.

If C could have a consistent set of rules, and/or easily tag something as undefined a la "unsafe" or have some sort of visual reminder signal (like using function name prefixes or suffixes) that would go a long way to making it better.

> The problem with c is that you must have a comprehensive dictionary in your brain with tons of corner cases to know what is or is not undefined in any given compiler setting.

I'm reminded of a quote: [0]

> Ada has made you lazy and careless.

> You can write programs in C that are just as safe by the simple application of super-human diligence.

To your point about performance:

> compiler can make choices based on certain assumptions in the name of performance

I don't think the performance argument really applies with modern optimising compilers. The (too often overlooked) Ada language is safer than C, but has about the same performance, provided you avoid the features with runtime overhead. Similarly I don't think the performance of Rust, and in particular its Safe Rust subset, suffers much for its lack of undefined behaviour.

It's true that, say, Java, doesn't perform as well as C even today, but Java requires a slew of runtime checks and is hostile to micro-optimised memory-management. In Ada, things like array bounds checks can be enabled for debug builds but disabled for production builds, which isn't easy to do in C.

> If C could have a consistent set of rules, and/or easily tag something as undefined a la "unsafe" or have some sort of visual reminder signal (like using function name prefixes or suffixes)

This essentially can't be done. Even the MISRA C coding style, which aims to help with this kind of thing, can't completely guarantee to eliminate undefined behaviour from C codebases. To illustrate the challenge of 'containing the risk' with the C language, it's undefined behaviour to do this:

    int i; int j = i;
Fortunately other languages do a much better job at offering truly safe subsets (Rust and D for instance).

[0] https://people.cs.kuleuven.be/~dirk.craeynest/quotes.html

> The problem with c is that you must have a comprehensive dictionary in your brain with tons of corner cases to know what is or is not undefined in any given compiler setting.

The cases of undefined behavior in the C standard are independent of compiler settings or options.

> If C could have a consistent set of rules …

The C language has a well-defined standard, but the presence of undefined behavior is a deliberate aspect of that standard.

Deliberateness is not the same as consistency.

You can have well defined standards, that are wildly inconsistent. For example, in python, in file A:

    def get(dict, key):
      return dict[key]
In file B:

    def get(key, dict):
      return dict[key]

Imagine working in this codebase!
I’m not saying it’s a bad thing, but it is something to be aware of
And program runs, and different times the same process execute them. Those two are what separate IB from UB on the original interpretation, from the last century.

But nowadays UB is something much more complex and dangerous than "I can't ever know the results of this".

Right. Personally, I think those could have been better phrased as "I can't tell". As for C's simplicity, 100% what you said.
> Even including knowledge of what is IB and UB, C is still simpler than most languages in common use these days.

That depends what you mean by simple. C is a fairly small language, but it has far more than its share of footguns.

In terms of compiler engineering, sure, C is comparatively simple.

>C is still simpler than most languages in common use these days.

Having less keywords and implementing less fancier concepts

doesn't make my day2day life easier, actually it usually makes my day harder.

Would you write a web app in it? (Just out of interest. I'm not trying to be an ass.)
No, wrong level of abstraction. Why do manual memory management in a realm where it doesn’t really matter? In addition to the excessive amount of work (also why I wouldn’t choose Rust for the job), you’re opening yourself up to a whole class of errors for no good reason.
I've written plenty of C web apps back in the old cgi-bin days, for no particular reason, and haven't found the memory management an issue. cgi-bin is a great example of a lifetime-managed execution environment where you can just use the heap as one big arena allocator, with malloc() having unchanged semantics (or, if you're feeling fancy, going to a bump allocator), and free() being no-op'd (or, more realistically, just omitted when writing code). Yeah, your high water mark memory usage might be a bit higher than a more managed approach, but the OS is a perfect garbage collector, and the fastest possible garbage collector, for short-lived executables.

The bigger issue is the mediocre string processing libraries that are so common to C.

I wrote my first web app in C (1999ish). Emitting HTML was way easier than any GUI libraries I had encountered up to that point.

I probably wouldn't write one in C today, but webapps are one of the easier string-heavy things to write in C[1]; you can get away with using a hierarchical memory manager and just free everything after the request is complete.

1: Having to do a lot of string manipulation is usually a good sign "you shouldn't be using C" There's a reason awk was written in 1977.

if it runs on a microcontroller, then yes