Live data from Hacker News

C Style: My favorite C programming practices (2014)

github.com

71–80 of 139 posts

Re: C Style: My favorite C programming practices (2014)

#71
post #49

Earlier quoted context omitted.

au contraire! considering programming involves a lot of reading, it overlaps (or even comes from) with. best practices from ye olde tradition of typesetting https://en.m.wikipedia.org/wiki/Line_length#:~:text=Traditio... . Aside books and print magazines and newspapers, we still respect that on web sites when reading is involved, why should programming be exempt of ergonomy?

programming involves a lot of reading Is that true for an average developer, really? Yes, we read lots of manuals, snippets, stackoverflows. But code? One does mostly write code. And when we do read code, it may lack good naming, structure, comments, clarity, may be unnecessarily complex or hacky. Where does it wrap is the thing one would care about only in perfect code, if at all. Most editors can smart-wrap and cle…

> Is that true for an average developer, really? Yes, we read lots of manuals, snippets, stackoverflows. But code? One does mostly write code.

No, every developer almost certainly reads a lot more code than they write. You can't modify code to add a feature without reading and understanding the code first. The code you add is often very short compared to the code you need to read to understand what to modify.

Re: C Style: My favorite C programming practices (2014)

#72

Earlier quoted context omitted.

Are there C++ libs that use floating points for timestamps? I was under the impression that most stacks have accepted int64 epoch microseconds as the most reasonable format.

> int64 epoch microseconds surely nanoseconds is the truth.

LONG_MAX nanoseconds is just Friday, April 11, 2262 11:47:16.854 PM, not exactly a future-proof approach. I guess having Tuesday, September 21, 1677 12:12:43.145 AM as the earliest expressible timestamp neatly sidesteps the problem of proleptic Gregorian vs Julian calendars.

Re: C Style: My favorite C programming practices (2014)

#73

Earlier quoted context omitted.

I'm torn both ways on the double issue. On the one hand, doubles are much more widely supported these days, and will save you from some common scenarios. Timestamps are a particular one, where a float will often degrade on a time scale that you care about, and doubles not. A double will also hold any int value without loss (on mainstream platforms), and has enough precision to allow staying in world coordinates for 3…

Are there C++ libs that use floating points for timestamps? I was under the impression that most stacks have accepted int64 epoch microseconds as the most reasonable format.

I think Apple is still doing that: https://developer.apple.com/documentation/foundation/nstimei...

Couple decades ago Microsoft did that too, VT_DATE in old OLE Automation keeping FP64 value inside. Luckily, their newer APIs and frameworks are using uint64 with 100-nanoseconds ticks.

Re: C Style: My favorite C programming practices (2014)

#74

While I don't agree every single point (see below), one thing great about this document is that the author tried to really elaborate one's opinion. That makes a good point to start the discussion regardless of my own opinion. Thus I'll contribute back by giving my own judgement for every single item here: Absolute agreement * Always develop and compile with all warnings (and more) on * #include the definition of ever…

> * No global or static variables if you can help it (you probably can)

I can't imagine doing this on embedded systems.

Re: C Style: My favorite C programming practices (2014)

#75

> 80-characters-per-line is a de-facto standard for viewing code. Readers of your code who rely on that standard, and have their terminal or editor sized to 80 characters wide, can fit more on the screen by placing windows side-by-side. This is one of the silliest practices to still be enforced or even considered in 2024. “Readers” should get a modern IDE/text editor and/or modern hardware.

On my 4K monitor, I use 4-5 vertical splits and 2-3 horizontal splits. The 80 column rule makes each of these splits readable, and allows me to see the full context of a chunk of kernel code or firmware at once. It has nothing to do with "modern" hardware or "modern" IDEs. It has everything to do with fitting the most amount of relevant information that I can on the screen at once, in context, and properly formatted for reading.

The 80 column rule may seem arbitrary, but it really helps analysis. I avoid open source code that ignores it, and I'll ding code that violates it during code review.

If I had code marching off the screen, or rudely wrapped around so it violated spacing, I'd have to reduce the number of splits I used to see it, and that directly impacts my ability to see code in context. Modern IDEs don't reduce the need to see things in context. It's not a matter of organizing things in drop-down menus, smart tabs, font changes, or magic "refactor" commands. Verifying function contracts in most extant software -- which lacks modern tooling like model checking -- requires verifying these things by hand until these contracts can be codified by static assertions. This, in turn, requires examining function calls often 5-6 calls deep to ensure that the de facto specifications being built up don't miss assumptions made in code deep in the bowels of under-documented libraries. I'd be terribly upset if I had to try to do this in code that not only missed modern tooling but that was written by a developer who mistakenly believed that "80 columns is for geezers." I freely admit that, at 43, I probably count as a "geezer" to many young developers. But, that doesn't change the utility of this rule. Violations of contracts in software account for a large percentage of errors in software AND security vulnerabilities. Most of these violations are subtle and easy to miss unless you can see the call stack in context. No developer can keep hundreds of details from code that they did not write in their head with perfect clarity. It's incredibly nice to have uniform style and uniform maximum line lengths. By convention, 80 columns has shown itself to be the most stable of these limits.

Even FAANG companies like Google follow this rule.

Re: C Style: My favorite C programming practices (2014)

#76

While I don't agree every single point (see below), one thing great about this document is that the author tried to really elaborate one's opinion. That makes a good point to start the discussion regardless of my own opinion. Thus I'll contribute back by giving my own judgement for every single item here: Absolute agreement * Always develop and compile with all warnings (and more) on * #include the definition of ever…

> * No global or static variables if you can help it (you probably can) I can't imagine doing this on embedded systems.

That's what I meant by "some obvious exceptions" :-)

Re: C Style: My favorite C programming practices (2014)

#78
post #18

> developers have a hope of being able to determine which #includes can be removed and which can't Can’t a modern compiler do that already? Didn’t google but seems an obvious compiler feature at the very least behind a warning flag.

I'm using https://github.com/include-what-you-use/include-what-you-use in preference over clang-tidy.

Re: C Style: My favorite C programming practices (2014)

#80
I agree with most, and most of the others I might quibble with, but accept.

However, the item to not use unsigned types is vastly stupid! Signed types have far more instances of UB, and in the face of 00UB [1], that is untenable.

It is correct that mixing signed and unsigned is really bad; don't do this.

Instead, use unsigned types for everything, including signed math. Yes, you can simulate two's complement with unsigned types, and you can do it without UB.

On my part, all of my stuff uses unsigned, and when I get a signed type from the outside, the first thing I do is convert it safely, so I don't mix the two.

This does mean you have to be careful in some ways. For example, when casting a "signed" type to a larger "signed" type, you need to explicitly check the sign bit and fill the extension with that bit.

And yes, you need to use functions for math, which can be ugly. But you can make them static inline in a header so that they will be inlined.

The result is that my code isn't subject to 00UB nearly as much.

[1]: https://gavinhoward.com/2023/08/the-scourge-of-00ub/

Post reply on HN