Live data from Hacker News

My personal C coding style as of late 2023

nullprogram.com

31–40 of 466 posts

Re: My personal C coding style as of late 2023

#31
I might just be a grumpy old dev but a lot of this stuff gets an immediate no from me because it’s so unidiomatic. You have to unlearn the accepted way of doing things and you end up with a codebase that is just so foreign to anyone looking at even a small chunk of it, unless they are committed to really learning to do things your way.

Everyone knows what a uint32_t is when they see it. The cognitive overhead (until it becomes second nature, obviously) just feels like a heavy price to pay in order to save yourself a few characters.

(Some other stuff in the proposed coding style still gets a thumbs up from me, though.)

Re: My personal C coding style as of late 2023

#32
typedef all structs - yes, helps with conciseness. Use typedefs liberally, I say. But only typedef the things themselves, not pointers to the things. You can always use (type *) when you need a pointer. In particular, for function pointers, typedef the function, not the function pointer. Then you can use the function typedef for function declarations too, which gives you parameter type checking without needing to fix declarations everywhere if you change a function signature. I see most C codebases get this one wrong, typedef'ing the function pointer and still needing to manually write out all function declarations for that pointer definition.

I'm not sold on the structs as return types thing. I prefer just a numeric error code as a return value, and out parameters for any other returns.

Re: My personal C coding style as of late 2023

#33
> #define sizeof(x) (size)sizeof(x)

I'm guessing this is lacking an outer pair of parentheses (i.e. it's not `((size)sizeof(x))`) on the grounds that they're unnecessary. In terms of operator precedence, casting binds tightly, so if you write e.g. `sizeof(x) * 3`, it expands to `(size)sizeof(x) * 3`, which is equivalent to `((size)sizeof(x)) * 3`: the cast happens before the multiplication. Indeed, casting binds more tightly than anything that could appear on the right of sizeof(x) – with one exception which is completely trivial.

But just for fun, I'll point out the exception. It's this:

    (size)sizeof(x)[y]
Indexing binds more tightly than casting, so the indexing happens before the cast. In other words, it's equivalent to `(size)(sizeof(x)[y])`, not `((size)sizeof(x))[y]`.

But you would never see that in a real program, since the size of something is not a pointer or array that can be indexed. Except that technically, C allows you to write integer[pointer], with the same meaning as pointer[integer]. Not that anyone ever writes code like that intentionally. But you could. And if you do, it will compile and do the wrong thing, thanks to the macro lacking the extra parentheses.

…On a more substantive note, I quite disagree with the claim that signed sizes are better. If you click through to the previous arena allocator post, the author says that unsigned sizes are a "source of defects" and in particular the code he presents would have a defect if you changed the signed types to unsigned. Which is true – but the code as presented also has a bug! Namely, it will corrupt memory if `count` is negative. You could argue that the code is correct as long as the arguments are valid, but it's very easy for overflow elsewhere in the code to make something accidentally go negative, so it's better for an allocator not to exacerbate the issue.

With unsigned integers, a negative count is not even representable, and a similar overflow elsewhere in the program would instead give you an extremely high positive count, which the code already checks for.

Personally I prefer to use unsigned integers but do as much as possible with bounds-checked wrappers that abort on overflow. Rarely does the performance difference actually matter.

Re: My personal C coding style as of late 2023

#34

I might just be a grumpy old dev but a lot of this stuff gets an immediate no from me because it’s so unidiomatic. You have to unlearn the accepted way of doing things and you end up with a codebase that is just so foreign to anyone looking at even a small chunk of it, unless they are committed to really learning to do things your way. Everyone knows what a uint32_t is when they see it. The cognitive overhead (until…

Unpopular opinion: something being unusual does not necessarily mean it is bad. Yes, it will look foreign to random people looking at it, but if someone wants to seriously work with it, it will only take a few days to get familiarised with it. The justification of "cognitive overhead" is, from what I have seen, a shibboleth for rejecting "outsider" code written by someone not conforming to the language standards by claiming it is harder to understand. Personally, I would say that says more about the person's inflexibility and/or OCD, not the writer's style.

I am not saying every style is good (some simply obfuscate things and/or make things overly verbose or unreadable) but rejecting a style solely based on it being "non-idiomatic" is not a good thing.

Re: My personal C coding style as of late 2023

#35
post #21

> To beginners it might seem like “wasting memory” by using a 32-bit boolean Maybe I'm a beginner then. He lists a few cases where it's not worse than sticking to 8-bit bools, but no cases where it's actually an improvement. It still wastes memory sometimes, e.g. if you have adjacent booleans in a struct, or boolean variables in a function that spill out of registers onto the stack. Sure it's only a few bytes here an…

It depends entirely on the architectures | CPUs, that said the obvious case from past experience is numeric processsing jobs where (say) you flow data into "per cycle" structs that lead with some conditionals and fill out with (say) 512 | 1024 | 2048 sample points for that cycle (32 or 64 bit ints or floats) .. the 'meat' of the per cycle job. My specific bug bear here was a junior who insisted "saving space" by pack…

But if you don't use packed attributes, then the compiler will still add padding as necessary to avoid misalignment, while not wasting space when that's not necessary.

Re: My personal C coding style as of late 2023

#38

I might just be a grumpy old dev but a lot of this stuff gets an immediate no from me because it’s so unidiomatic. You have to unlearn the accepted way of doing things and you end up with a codebase that is just so foreign to anyone looking at even a small chunk of it, unless they are committed to really learning to do things your way. Everyone knows what a uint32_t is when they see it. The cognitive overhead (until…

I want to both be polite to the OP but also agree.

Writing correct C is hard, so I’m not going to knock anyone who found stuff that helps them.

But pound defining shit to things you know via your Hungarian notion? Write some elisp. My Haskell programs don’t actually have Unicode lambda in them.

Pascal strings? Yeah, that’s probably the better call, but why not use C++ or Rust or something where a bunch of geniuses got it right already?

Re: My personal C coding style as of late 2023

#39
I like it a lot. Especially the part about ditching const qualifiers. They clutter function declarations, don't make the intent any clear, and almost never improve performance. Restrict, on the other hand, I've found makes the compilers emit better code in many cases.

But I don't like using 1 and 0 instead of booleans. Many standard C functions (fclose for example), return 0 on success. Better to be explicit here.

Post reply on HN