Live data from Hacker News

My personal C coding style as of late 2023

nullprogram.com

151–160 of 466 posts

Re: My personal C coding style as of late 2023

#152

Earlier quoted context omitted.

I mean, being a bit glib here, but a lot of programming is dealing with someone else's type system. Moreover, for those of us who write C fairly often, the mnemonics here are familiar. Actually, as custom type systems go, this one is pretty elegant. Reminds me of Rust.

Speaking of type systems, I read glib as g-lib a few times and tried to understand how you were talking about the GNU lib in that sentence.

Wouldn't that have to be `glibc`?

Re: My personal C coding style as of late 2023

#153

Earlier quoted context omitted.

> a proprietary fork of GCC A what now?

I think it's not a GPL violation if you keep the fork non-public. Though I'm entirely sure not when something is considered private or public. You can obviously make changes to a GPL repo, compile it and run the executable yourself and just never release the source code. But what happens when you start sharing the executable with your friends, or confine it to a company? "I made this GCC fork with some awesome featur…

My understanding is the violation happens when you share the binary without the license and sources, or information on how to request the sources.

Re: My personal C coding style as of late 2023

#154

Earlier quoted context omitted.

> a proprietary fork of GCC A what now?

I think it's not a GPL violation if you keep the fork non-public. Though I'm entirely sure not when something is considered private or public. You can obviously make changes to a GPL repo, compile it and run the executable yourself and just never release the source code. But what happens when you start sharing the executable with your friends, or confine it to a company? "I made this GCC fork with some awesome featur…

All the GPL says on source code access is that you need to make the source code available to whoever you distributed your program to. If the program never leaves a closed circle of people, neither does the source code.

Re: My personal C coding style as of late 2023

#155
post #86

Earlier quoted context omitted.

they're not quirky types in the least...

In isolation, they're not crazy. But much C code is bringing in library headers which contain their author's own pet choices for these, which inevitably are not the same and the result is extremely confusing when you have that in play as well as the stdint.h ones. The kernel contains a mixture of "pet" types like u32 and stdint ones, it's already confusing. He also does make a "crazy" choice later to call his string…

> which clashes with his nomenclature here.

How?

Re: My personal C coding style as of late 2023

#156

Earlier quoted context omitted.

Agreed; const is one of those features that is so good I wish a lot of other languages (e.g. java) had it.

FWIW, Java does have the "final" keyword.

Final only protects the variable from being assigned a new reference (similar to a const pointer). It doesn’t protect any of the underlying data held by the object from being changed, unless the entire hierarchy has every field declared final as well. I still use final heavily in all of my Java code, but it doesnt convey the full intent I would like it to.

Re: My personal C coding style as of late 2023

#157
In general, the style the author has adopted is to introduce brevity where he can, and use wrappers over what would have been standard and idiomatic C code. In most situations, these conventions aren't good in a non-solo project, because they simply aren't as obvious to the programmer.

He says so himself:

> I don’t intend to use these names in isolation, such as in code snippets (outside of this article). If I did, examples would require the typedefs to give readers the complete context. That’s not worth extra explanation. Even in the most recent articles I’ve used ptrdiff_t instead of size.

You require extra work to understand his basic types before reading even a short snippet, so he doesn't use it when he wants people to read short snippets.

Introducing additional stuff the programmer must remember that does not add any safety is pointless busywork.

A non-complete summary of his conventions:

1. typedef standard typenames to 3-char symbols,

2. remove qualifiers like const,

3. use macros to reduce the amount of typing the programmer does,

4. typedef all structs (and enums too, I assume)

5. A macro-ized string-typed with prefixed-length.

> Starting with the fundamentals, I’ve been using short names for primitive types. The resulting clarity was more than I had expected,

This isn't clear: `int8_t` is a lot clearer to a C programmer than `i8`, because a C programmer has already internalised the pattern of the stdint.h types. This is going to lead to subtle bugs as well: quick, according to his convention, what is the % specifier for `byte`?

You can use %c, but that gives you an ascii character (which is not what we think of when we say 'byte').

If you use PRIu8 the compiler might give warnings because `char` might be signed. The best option is to just not use `byte` and use `uint8_t` instead (or, in his system, `u8`).

Same with `b32` vs `i32` - it's a distinction without a difference and mixing these types won't give compiler warnings, while it is almost certainly an error on the part of the developer. Use `bool` if you don't like `_Bool`.

In general I try to take advantage of whatever typing C provides; I don't try to subvert it because I want the compiler to warn me when my intention doesn't match the code I wrote.

> No const. It serves no practical role in optimization, and I cannot recall an instance where it caught, or would have caught, a mistake.

I disagree with dropping `const`.

1. It's useful as an indicator to the caller that the returned value must/must not be freed. It's a convention I use that makes it easy to visually spot memory leaks.

Of the two functions below, it's clear to me which one needs the returned value `free()`ed and which one doesn't.

     const char *replace_substring (const char *src, const char *pat, const char *replacement);
     char *replace_substring (const char *src, const char *pat, const char *replacement);

2. It actually does catch a lot of problems, because the compiler warns me when I attempt to modify a value that some other code I wrote never intended to be modified. It's about intention, and when I know it is safe to modify the `const` value, then I have to explicitly cast away the const to compile my program. Anyone reading the program will know that the modification of the const-qualifed value is intentional, and therefore safe.

> #define s8(s) (s8){(u8 *)s, lengthof(s)}

This is interesting. I will try this out in my next project. I do think that there'll be quite a few compiler warnings for sign-mismatch though. This is the second "I wonder what the sign is" question for programmers reading his code - it means that his code has to compile with the flags that he compiles it with (I assume he's passing a flag to force chars to a particular sign). You can't simply compile his code in another project unless you copy his flags, and those flags may conflict with the new projects flags.

I also wish that he'd showed a few examples of how having the length helps - what is presented in the post doesn't show any additional string safety over using nul-terminated strings. All those macros, including the one that creates the struct, could be written to operate on null-terminated strings. In essence, the length can be simply unused for everything! Where's the safety!?

> It’s also led to a style of defining a zero-initialized return value at the top of the function, i.e. ok is false, and then use it for all return statements. On error, it can bail out with an immediate return.

I use a similar pattern, but I use `goto cleanup` on all errors; you can't, as a general pattern, return early in a non-trivial C function without leaking resources. You can, as a general pattern, `goto cleanup` in every C function to clean up resources. I prefer the general pattern that I use everywhere rather than having to ensure that all resources acquired up to that particular return statement are released.

> rather than include windows.h, write the prototypes out by hand using custom types.

I think this is a very bad idea: you can't depend on the headers not changing after a compiler or library update. Sure, maybe in practice, all the Windows types and declarations don't change all that much, but I wouldn't want to be the developer trying to hunt down a bug because the interface to some function has changed and the compiler isn't giving me errors.

All in all, I dunno if I would look forward to working on a team with these conventions - the code is harder to read, doesn't work in isolation, needs custom flags, and introduces a string type without introducing any string safety with it.

Re: My personal C coding style as of late 2023

#158
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…

At one point a loooooong time ago we said "let's give every struct its own page" as a joke but... holy crap, it was so much faster.

Re: My personal C coding style as of late 2023

#159

IMO, defining your own types is one step too far. Now everyone who is already familiar with C types has to learn your own quirky system to understand one program. I think it does probably make sense to be specific about the sizes though e.g. using uint32_t over just uint (and expecting to receive some architecture-dependent size you might not get with uint.) These types should be defined in the right header (I think…

The author did qualify it with personal coding style. Frankly the standard types are too verbose and I wish this guy's elegant and clear list had been the one that was adopted way back when.

> The author did qualify it with personal coding style. Frankly the standard types are too verbose and I wish this guy's elegant and clear list had been the one that was adopted way back when.

They didn't adopt it for the same reason that it is a bad idea now - too many programs already contained at least one variable named after his types.

If the standard had adopted his convention, too many programs will break, which is why his convention is currently unsuitable for any existing project.

Re: My personal C coding style as of late 2023

#160
post #110
post #7

A lot of this makes sense to me. I’ve started writing a bare metal OS for Arm64. It’s very early but I’ve done some similar things. I’m using pascal strings, I’ve also renamed the types (though I’m using “int8” style, not “i8”). I quickly decided that I never intend to port real software to it, so I really don’t have to conform to standard C library functions or conventions. That’s given me more freedom to play aroun…

> I never intend to port real software to it, so I really don’t have to conform to standard C library functions or conventions. So you're just building it as just a hobby, won’t be big and professional like gnu?

Context: Linus Torvalds' announcement of Linux to comp.os.minix: https://www.cs.cmu.edu/~awb/linux.history.html
Post reply on HN