This was very interesting, and it's obvious from the majority of the text that the author knows a lot about these languages, their implementation, benchmarking corners, and so on. Really!
Therefore it's very jarring with this text after the first C code example:
This uses a static variable to have it persist between both the compare function calls that qsort makes and the main call which (potentially) changes its value to be 1 instead of 0
This feels completely made up, and/or some confusion about things that I would expect an author of a piece like this to really know.
In reality, in this usage (at the global outermost scope level) `static` has nothing to do with persistence. All it does is make the variable "private" to the translation unit (C parliance, read as "C source code file"). The value will "persist" since the global outermost scope can't go out of scope while the program is running.
It's different when used inside a function, then it makes the value persist between invocations, in practice typically by moving the variable from the stack to the "global data" which is generally heap-allocated as the program loads. Note that C does not mention the existence of a stack for local variables, but of course that is the typical implementation on modern systems.
I'm finding myself in a weird position now, because I disagree with a whole lot of things in the blog post (well, the parts I was willing to read anyways), but calling that variable static for the sake of persistence was correct.
The fact that you are questioning the use of the term shows that you are not familiar with the ISO C standard. What the author alludes to is static storage duration. And whether or not you use the "static" keyword in that declaration (also definition), the storage duration of the object remains "static". People mostly call those things "global variables", but the proper standardese is "static storage duration". In that sense, the author was right to use "static" for the lifetime of the object.
EDIT: if you drop "static" from that declaration, what changes is the linkage of the identifier (from internal to external).
>This uses a static variable to have it persist between both the compare function calls that qsort makes and the main call which (potentially) changes its value to be 1 instead of 0
The only misleading thing here is that ‘static’ is monospaced in the article (this can’t be seen on HN). Other than that, ‘static variable’ can plausibly refer to an object with a static storage duration, which is what the C standard would call it.
>moving the variable from the stack to the "global data" which is generally heap-allocated as the program loads
It is not heap-allocated because you can’t free() it. Non-zero static data is not even anonymously mapped, it is file-backed with copy-on-write.
I had a completely different response reading the sentence. I've been programming in C for 20+ years and am very familiar with exactly the problem the author is discussing. When they referred to a "static variable", I understood immediately that they meant a file static variable private to the translation unit. Didn't feel contrived or made up to me at all; just a reflection of the author's expertise. Precision of language.
I mean, you're closer to the committee than I am, but while that is true in a literal sense, I'd assume that you all would not let someone who knew how to edit LaTeX but not know anything about C hold that position.
Assuming we have some choice. Not many people volunteer their time to this work, which is quite a lot and not much fun. Companies also do not invest a lot of resources into C.
It took me a second read to realise that the mention of static is a red herring. I think the author knows that the linkage is irrelevant for the rest of the explanation; it just happens to be static so they called it static. But by drawing attention to it, it does first read like they're confused about the role of static there.
Oh! Thanks, I was not being as concrete as I imagined. Sorry.
Yes, the `static` can simply be dropped, it does no additional work for a single-file snippet like this.
I tried diving into Compiler Explorer to examine this, and it actually produces slightly different code for the with/without `static` cases, but it was confusing to deeply understand quickly enough to use the output here. Sorry.
I see exactly the same assembly from x86-64 GCC 15.2 with -O2 the first example in the article both as is and without `static`, which makes sense. The two do differ if you add -fPIC, as though you’re compiling a dynamic library, and do not add -fvisibility=hidden at the same time, but that’s because Linux dynamic linking is badly designed.
I vaguely remember a reference to some balance game as the origin story for the Guru Meditation, but that was so long ago and I never looked it up!
Meta: it would have been nice to include this reference in the submission title, since it's least as interesting as the fact that the peripheral was for the Atari 2600. Something like "The Joyboard: Atari 2600 balance peripheral that inspired Guru Meditation", perhaps. Probably too late now, and this is not exactly tearing down the front page, anyway. :)
I have also heard about deployment of inference (LLMs etc) instead of crypto at these gas turbines. If you already have internet there, why not I guess.
Quite interesting, and felt fairly "modern" (which for C programming advice sometimes only means it's post-2000 or so). A few comments:
----
This:
struct Vec3* v = malloc(sizeof(struct Vec3));
is better written as:
struct Vec3 * const v = malloc(sizeof *v);
The `const` is perhaps over-doing it, but it makes it clear that "for the rest of this scope, the value of this pointer won't change" which I think is good for readability. The main point is "locking" the size to the size of the type being pointed at, rather than "freely" using `sizeof` the type name. If the type name later changes, or `Vec4` is added and code is copy-pasted, this lessens the risk of allocating the wrong amount and is less complicated.
----
This is maybe language-lawyering, but you can't write a function named `strclone()` unless you are a C standard library implementor. All functions whose names begin with "str" followed by a lower-case letter are reserved [1].
----
This `for` loop header (from the "Use utf8 strings" section:
for (size_t i = 0; *str != 0; ++len)
is just atrocious. If you're not going to use `i`, you don't need a `for` loop to introduce it. Either delete (`for(; ...` is valid) or use a `while` instead.
----
In the "Zero Your Structs" section, it sounds as if the author recommends setting the bits of structures to all zero in order to make sure any pointer members are `NULL`. This is dangerous, since C does not guarantee that `NULL` is equivalent to all-bits-zero. I'm sure it's moot on modern platforms where implementations have chosen to represent `NULL` as all-bits-zero, but that should at least be made clear.
Where would you put it? The const of the pointer is not the main point, it's just extra clarity that the allocated pointer is not as easily overwritten which would leak the memory.
[1] agrees that World War II-era luminous materials featured radium, yes. Another use seems to have been putting discs on helmet fronts of paratroopers, to help soldiers see each other in the dark.
This page [2] has a picture of a variety of luminous products from the era, and also mentions one civilian usage was marking edges of clothing, also to help make pedestrians more visible in the (blacked-out) streets.
I'm rather low on the Interest in History scale, but it's fascinating how often WW2 manages to deliver something new. Thanks.
All told, 69 of the 300 items came up higher at the register: a 23% error rate that exceeded the state’s limit by more than tenfold.
This implies that an error rate of perhaps 2% would be legal. I haven't checked, but I guess Europe has something similar even though I'm quite certain that retailers have to sell things at the posted price if there's a mistake.
Part of the problem seems to be that the maximum fine (at least in the state in the article) is "too low", so retailers don't have an incentive to keep price tags correct since they profit from the error and even if they're fined it's still better (economically) for them to charge more than the price tag. I wonder how much lobbying has happened to keep fines low ...
The interesting question would be how many products came in lower, but sadly the article doesn't include that.
If 23% were higher and 23% were lower then you could make a reasonable argument that it's just incompetence from the store.
But if 23% are higher and none are lower, then that looks a lot more like malice - because the odds of you happening to have a 23% error rate than just happens to always work out in the retailer's favour are basically zero.
__attribute__((maybe_unused)) or [[maybe_unused]] or such things (dependin on ur spec version i guess?) can be used not to disable a whole line of errors.
a) __attribute__((warn_unused_result)) is non-standard in the first place, are you looking for [[nodiscard]] - GCC does not warn on cast to void with that?
b) A return value that is explicitly marked like this is very different from an unused variable that gp suggested the cast to void idiom for. GCC does not warn on variables that are unused except for a cast to void.
I want some defined way to tell the compiler that I am intentionally ignoring the result.
I encounter this when trying to do best-effort logging in a failure path. I call some function to log and error and maybe it fails. If it does, what, exactly, am I going to do about it? Log harder?
When my database logging fails, I write a file that logs the database fail (but not the original log file).
When my file logging fails, depending on application, I'll try another way of getting the information (the fact that for file logging failed) out - be that an http request or an email or something else.
Databases fail, file systems fill up. Logging logging failures is extremely important.
I like to have a separate monitoring process that monitors my process and a separate machine in a different datacenter monitoring that. But at the end of the day, the first process is still going to do try to log, detect that it failed, try the final backup log and then signal to its monitor that it’s in a bad state. It won’t make any decisions that depend on whether the final backup logging succeeds or fails.
I'm not working on anything life-critical, one additional layer of redundancy is all I budget for. If both my database is down and my local filesystem is full simultaneously, things have gone bad and I've likely got lots of other symptoms I'm going to find to direct me.
Sometimes. For example, you might be setting a non-crucial option on a socket, and if it fails you don't even care to log the fact (maybe the logging would be too expensive), so you just ignore the return value of whatever library is wrapping setsockopt.
reply