Live data from Hacker News

A critique of "How to C in 2016"

github.com

51–60 of 181 posts

Re: A critique of "How to C in 2016"

#51

Earlier quoted context omitted.

Because it's simple and low-overhead and compilers for it exist on every lump of hardware I've ever had to work with, from a clunky x64 to a PIC to a TigerSHARC to a bizarre DSP thingy from a tiny fab lab somewhere. A great many of the problems that people experience with C code can actually be nullified (zing!) by finding a competent C programmer who does the job properly. A tool being easy to misuse doesn't mean we…

Those compilers exist because of path dependency from unix not from any unique qualities of C

This makes no sense and I believe you are incorrect. When Analog Devices churned out the TigerSHARC processor, they did not decide to write a C compiler for it because of unix path dependencies.

Re: A critique of "How to C in 2016"

#52
> Converting to uintprt_t will give you some result -- but that result won't be useful. Unless you're writing low-level system code, don't do any pointer comparison or arithmetic unless both pointers point into or just past the end of the same object.

I disagree. There are situations where you need an ordering between unrelated objects, but the precise order doesn't matter, only that it's consistent.

An example is when you have a complex data structure with one lock per node, and you need to lock more than one node at a time for some algorithm.

To prevent a deadlock, you must always take the locks in the same order. Comparing the address of the locks gives you a total order over all the locks, which is enough.

Re: A critique of "How to C in 2016"

#53
post #35

>size_t is defined as "an integer capable of holding the >largest array index" >>No, it isn't. Could anyone elaborate? I don't see how could someone allocate more than SIZE_MAX bytes with (m/c/re)alloc since they all take size_t as an argument, and size_t is the type used for defining array sizes. Thus size_t can hold the largest array index (in fact it can hold the largest_index+1 since arrays are zero based). Any c…

Maybe he's taking it very literally, as I think size_t is literally defined as 'the integer type of the result of the sizeof operator'. So it literally isn't defined as 'an integer capable of holding the >largest array index' as that's not the definition and words they use.

But if sizeof returns size_t, then your can't have indexes larger than that. Otherwise you could point beyond the largest in-memory object possible. (Using smallest (byte) indexing)

But yes, he may be arguing the definition rather than meaning.

Re: A critique of "How to C in 2016"

#54

Earlier quoted context omitted.

By the same argument we shouldn't assume that bits have only two values - what, you mean I can't write C for my ternary logic computer? You need to make a decision about which simplifying assumptions you make - C has decided not to assume there are 8 bits to the byte. I think it's arguable that in 2016 this is not the best decision, and they could get rid of some cognitive overhead by making the simplifying assumptio…

Unfortunately, there are real world systems with C compilers that do not have 8 bit bytes. It's easy to forget the embedded world. C is one of the very, very few languages that you can reasonably expect to run on your weird embedded microprocessor, microcontroller, DSP, or whatever. Bit, however, means "binary digit". That's the literal definition of the word. Historical usage of the word "byte" has varied.

> C is one of the very, very few languages that you can reasonably expect to run on your weird embedded microprocessor, microcontroller, DSP, or whatever.

I'm not an expert on DSP processing in any way, but I'd argue that if the environment is so peculiar that it doesn't have 8-bit bytes, you won't be able to use so many of the (formally optional) parts of C that you might as well call your code "weirdC" and do without char. It's not like you're going to use normal C libraries, and you are most probably relying on a specific compiler implementation and a lot of platform specific weirdnesses.

Re: A critique of "How to C in 2016"

#55

Earlier quoted context omitted.

Again, if people can't agree what type to use for integers, then it's not "simple". And yes, a tool being easy to misuse absolutely means we shouldn't use it unless we have to. A competent adult would never use a chainsaw or a scalpel except for tasks where nothing else would work.

Pick the integer type that is best suited for your use, given your circumstances. I can't make it any simpler. There is no one true magical perfect solution for all circumstances in all places at all times. This is why I employ competent programmers; to make these choices. A competent adult would never use a chainsaw or a scalpel except for tasks where nothing else would work. Of course they would. I do, frequently;…

>Pick the integer type that is best suited for your use, given your circumstances.

>Pick the fission reactor type that is best suited for your use, given your circumstances.

Re: A critique of "How to C in 2016"

#56
I find myself to disagreement with almost ALL the points this "critique" makes.

They are either minor pedantic corrections, "it's how it's always been done" things, or "you might have your reasons for doing it in a bizarro way" affairs.

Sorry, but for 90% of use cases, the original article has better advice.

Re: A critique of "How to C in 2016"

#57
> int in particular is going to be the most "natural" integer type for the current platform. If you want signed integers that are reasonably fast and are at least 16 bits, there's nothing wrong with using int

The slight performance gain on a few systems that you get from using int rather than int16_t is very rarely worth the hugely increased risk of introducing platform-specific undefined behaviour, IMO.

> float and double are very commonly IEEE 32-bit and 64-bit floating-point types, particularly on modern systems, but there's no guarantee of that in the language.

True. Is there an alternative? Something like float32_t?

> But more often all you need is a particular range of values. For that, you can use either the [u]int_leastN_t or [u]int_leastN_t types, or one of the predefined types.

Sure - but again, how much performance do you gain from using a _leastN type, and how much reliability do you lose?

> It's capable of holding the size of the largest object your implementation supports. (There's an argument that that's not necessarily guaranteed, but for practical purposes you can rely on it.) It can hold the largest memory offset if all offsets are within a single object.

But you just said in the previous section that it only makes sense to perform pointer arithmetic within a single object anyway.

> There is a widespread convention, particularly in Unix-like systems, for functions to return 0 for success and some non-zero value (often -1) for failure. In many cases different non-zero results denote different kinds of failure. It's important to follow this convention when adding new functions to such an interface. (0 is used for success because typicallyi there's only one way for a function to succeed, and multiple ways for it to fail.)

The convention is not as widely accepted as this section implies. When adding to an existing system one should follow that system's conventions. When writing for Unix one should follow the Unix conventions. But there are other conventions (e.g. the VMS one) that also see use in C.

> I don't often use automatic formatting tools myself. Perhaps I should.

Yes, you should.

> Zeroing memory often means that buggy code will have consistent behavior; by definition it will not have correct behavior. And consistently incorrect behavior can be more difficult to track down.

Disagree strongly. Consistently incorrect behaviour is much easier to track down than inconsistently incorrect behaviour.

> if you're trying to program defensively, you might consider initializing allocated memory to some value that's known to be invalid rather than one that might be valid.

Agreed - but how? One of the biggest problems with C is that it is extremely hard to mark a state as invalid (hence the whole integers for error codes discussion earlier, where really an error code should have a different type from a valid integer result).

Re: A critique of "How to C in 2016"

#58
post #25

Earlier quoted context omitted.

Because it's simple and low-overhead and compilers for it exist on every lump of hardware I've ever had to work with, from a clunky x64 to a PIC to a TigerSHARC to a bizarre DSP thingy from a tiny fab lab somewhere. A great many of the problems that people experience with C code can actually be nullified (zing!) by finding a competent C programmer who does the job properly. A tool being easy to misuse doesn't mean we…

See, that is the problem right there. Even if one does find such competent programmers, I doubt they the way C culture works it would help. Most C devs I have met, if given a memory safe systems programming language like Modula-2 or Rust, would just use SYSTEM or unsafe {} everywhere without any proof of a profiler if it really matters to the customer. As for being available everywhere, that is an historical accident…

heck, even in c# I use unsafe{} here and there ((

Re: A critique of "How to C in 2016"

#59
post #35

>size_t is defined as "an integer capable of holding the >largest array index" >>No, it isn't. Could anyone elaborate? I don't see how could someone allocate more than SIZE_MAX bytes with (m/c/re)alloc since they all take size_t as an argument, and size_t is the type used for defining array sizes. Thus size_t can hold the largest array index (in fact it can hold the largest_index+1 since arrays are zero based). Any c…

The counterargument is actually relatively simple, because it's an argument over what the definition of size_t is, and you can simply go look to the C standard and find the definition there.

Re: A critique of "How to C in 2016"

#60
post #35

>size_t is defined as "an integer capable of holding the >largest array index" >>No, it isn't. Could anyone elaborate? I don't see how could someone allocate more than SIZE_MAX bytes with (m/c/re)alloc since they all take size_t as an argument, and size_t is the type used for defining array sizes. Thus size_t can hold the largest array index (in fact it can hold the largest_index+1 since arrays are zero based). Any c…

The counterargument is actually relatively simple, because it's an argument over what the definition of size_t is, and you can simply go look to the C standard and find the definition there.

I understand.

If I change the argument to: size_t is capable of holding the largest array index", then this must be correct, or is there still something I missed?

Post reply on HN