I get that everyone has their own coding style, but ditching established conventions in C for personal aesthetic seems a bit much. Like, using u8 or i32 instead of the standard uint8_t or int32_t might save a few keystrokes, but it could confuse anyone else looking at the code. And the custom string type over null-terminated strings? C's built around those, and deviating from that just feels like making life harder f…
> Like, using u8 or i32 instead of the standard uint8_t or int32_t might save a few keystrokes [...] It is not about saving keystrokes, it is about reducing sensory load when reading it. Sorry, I know it may sound like I'm splitting hairs, but every single time when the argument of verbosity vs conciseness in programing languages comes around, this "keystrokes" argument is thrown and it is extremely flawed. The core…
My personal C coding style as of late 2023
421–430 of 466 posts
Re: My personal C coding style as of late 2023
#422Re: My personal C coding style as of late 2023
#423I 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 go…
Re: My personal C coding style as of late 2023
#424Great article. One thing for me is that I think we named our variables wrong. We should be specifying the number of bytes, not bits. I use U1, U2, U4, U8, I1, I2, etc Also S for "slot" aka unsigned pointer sized integer (usize_t) Another big point is formatting code to line-up instead of with an autoformatter. When you are doing something which is almost the same but slightly different it helps readability considerab…
Could you elaborate on the reasoning behind using byte length instead of bit length? Most of the time when I use fixed-width int types I’m trying to create guarantees for bitwise operators. From my perspective I feel like it therefore makes the most sense to name types on a per-bit level.
I also like that it makes all the type names the same width (notably U1/U2 vs u8/u16).
Re: My personal C coding style as of late 2023
#425Earlier quoted context omitted.
I agree. A lot of languages have settled on those same names or something similar. We don’t live in a world with a single word size anymore so carrying bit length in the name is critical, and so is keeping identifier names short. His trade off is exactly the one I would make.
> carrying bit length in the name is critical I beg to disagree. In D: byte - 8 bits short - 16 bits int - 32 bits long - 64 bits absolutely nobody is confused about this.
Re: My personal C coding style as of late 2023
#426Re: My personal C coding style as of late 2023
#427Earlier quoted context omitted.
Eh. I absolutely get what you're saying. And this is for sure flying very close to the knife's edge. But if your assertion checks don't run in release mode, and due to some bug, those invariants don't hold, well, your program is already going to exhibit undefined behaviour. Why not let the compiler know about the undefined behaviour so it can optimize better? The nice thing about this approach is that the assertion p…
> But if your assertion checks don't run in release mode, and due to some bug, those invariants don't hold, well, your program is already going to exhibit undefined behaviour. Why not let the compiler know about the undefined behaviour so it can optimize better? Usually in release mode you want to log the core dump and then fix the bug.
The unreachable pragma suggested by the author is just a more extreme version of the latter choice.
Re: My personal C coding style as of late 2023
#428Earlier quoted context omitted.
Unsigned doesn’t really bend any rules and their behavior around wraparound is well defined. Therefore there is another use case : circular buffer indices.
Yes it does bend rules. Say that a , b and c are small integers (we don't worry about addition overflow). Given an inequality formula like: a we can safely perform this derivation (add -b to both sides): a - b This is not true if a , b and c are unsigned. Or even if just one of them is, depending on which one. What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large val…
True, but this is not valid if they are signed, either. Take
a = INT_MIN
b = 1
c = 2
Then a
is true. But a - b
invokes undefined behavior.Edit: missed
> Say that a, b and c are small integers (we don't worry about addition overflow)
Ah, well that makes this example vacuously true, however I'm not sure what the utility in that restriction is. We've only moved the goalposts from "bend[ing] the rules of arithmetic around zero" to bending the rules of arithmetic outside of "small integers".
Re: My personal C coding style as of late 2023
#429Earlier quoted context omitted.
It's the reason Rust makes us use an exclamation mark with macro calls: beware! magic! here! I like this as a convention, but not necessarily as a grammar rule. Printing values is common enough that it shouldn't require shouting for constant attention, simple code shouldn't trigger sensory overload.
I do think that the default convention of SHOUT_CASE for constants in Rust is too in-your-face given that there's nothing about Rust constants that would particularly require them to stand out. I might have gone with CamelCase given that some things in Rust already straddle the "types are CamelCase, terms are snake_case" delineation (enum variants, even data-less ones, are CamelCase, as well as the implicitly defined…
Re: My personal C coding style as of late 2023
#430Earlier quoted context omitted.
Yes it does bend rules. Say that a , b and c are small integers (we don't worry about addition overflow). Given an inequality formula like: a we can safely perform this derivation (add -b to both sides): a - b This is not true if a , b and c are unsigned. Or even if just one of them is, depending on which one. What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large val…
> This is not true if a , b and c are unsigned True, but this is not valid if they are signed, either. Take a = INT_MIN b = 1 c = 2 Then a is true. But a - b invokes undefined behavior. Edit: missed > Say that a, b and c are small integers (we don't worry about addition overflow) Ah, well that makes this example vacuously true, however I'm not sure what the utility in that restriction is. We've only moved the goalpos…
We have moved the goalposts much farther apart.
If we are using a 32 bit integer type, all we need is that a, b and c fit into 31 bits. Then there is no way that b + c or a - b overflow. For a single addition or subtraction, we just need one bit of headroom.
I.e. the values do not actually have to be that small.
There are all kinds of situations in which programs work with small integers, where the calculations could bork if an unsigned creeps in.
A cliff near zero is qualitatively different from clipping at two extremes. An electronic device that clips everything below zero volts will distort even the faintest waveform. One that clips near the power rails has clean headroom.