The system call wrappers could all have explicitly set errno to 0 on success, but they didn't.
Because it's plainly unnecessary. It'd be a waste today, and even more so on a PDP-11 in the 1970s.
The system call wrappers could all have explicitly set errno to 0 on success, but they didn't.
Because it's plainly unnecessary. It'd be a waste today, and even more so on a PDP-11 in the 1970s.
This design choice reflects the POSIX philosophy of minimizing overhead and maximizing flexibility for system programming. Frequent calls to write(), for example, would be hindered by having to reset errno with each call/check of write() return value - especially in cases where a lot of write()'s are queued.
Or .. a library function like fopen() might internally call multiple system calls (e.g., open(), stat(), etc.). If one of these calls sets errno but the overall fopen() operation succeeds, the library doesn’t need to clear errno. For instance, fopen() might try to open a file in one mode, fail with an errno of EACCES (permission denied), then retry in another mode and succeed. The final errno value is irrelevant since the call succeeded.
This mechanism minimizes overhead by not requiring errno to be reset on success.
It allows flexible, efficient implementations of library and system calls and encourages robust programming practices by mandating return-value checks before inspecting errno.
It supports complex, retry-based logic in libraries without unnecessary state management - and it preserves potentially useful debugging information.
You only care about errno when you know an actual error occurred. Until then, ignore it.
This is similar to other systems-level things that can occur in such environments, for example when setting a hard Reset-Reason or Fail-Reason register in static/non-volatile memory somewhere, for later assessment.
IMHO, the thing thats most peculiar about this is that folks these days think of it as weird/quaint - when in fact, it makes a lot of sense if you think about it.
If its important to you to find these cases, use clang's static analyzer to perform deep source code analysis via scan-build. See also cppcheck and pc-lint, or PVS-Studio, each of which have means by which you can catch this error.
Plus, we're talking about POSIX here. You don't have a time machine. Shall we argue about just how much POSIX software is out there, working perfectly fine with this technique?
Sure, in New Fangled Language De Jour™, return as many tuples as your heart desires.
But don't expect POSIX to play along ..
I don’t really blame the people in 1970 for coming up with this design but it’s 2025 now; we can agree that it has problems. Tape recorders were also a neat idea but I can record a thousand times more on my phone now, often at higher quality. By modern standards, they suck.
"Pointers suck", for the same reason.
In any case, its the 21st century - if you're shipping C code that hasn't been statically analyzed with 100% code coverage, you're doing it wrong.
Besides which, this is an abstraction which, once done properly once, in a library or framework, can be ignored at higher levels of abstraction, or even language runtime/execution environments, with some degree of comfort ..
/ducks
I'd argue this is in spite of choosing a path that makes maintainable software more difficult than it needs to be. Constraints change over time, and the thought process that made this practice rational no longer coheres with modern-day constraints. Maintaining software is now (much, much) more expensive than the performance minutae that led to this cost.
> Sure, in New Fangled Language De Jour™, return as many tuples as your heart desires.
This isn't related to language at all—C may not have tuples, but structs are an equivalent.
Problem? Nope.
errno handling has been long since adopted as a best practice, industry-wide, and the only ones who are going to get toasty fingers on this issue are newbs, or those grey beards who still think code coverage and static analysis are new-fangled tools of the trade.
So I'd argue that this problem is a straw man, the OP is just trying to find something edgy to whine about, and that actually - really the issue is that programmers just don't like to read docs, don't like to comply or conform with long-since settled standards, and are too heavily inflicted in this day and age with neurotic violations of the DRY rule to actually check themselves (or errno) before they wreck themselves (or their i/o thread) ...
Global errno is a bad design that is a consequence of bad design in c. If c supported tagged unions and pattern matching, there would be no way to access the result or error value without first checking what type of value it is. But since c doesn't support this, all these apis require programmer discipline that cannot be relied upon. As a consequence, it becomes almost inevitable that you encounter some inscrutable bug that someone else wrote due to their lack of skill and/or discipline. That doesn't make sense to me though I do understand why it is the way it is.
This is the crux of all computerization and will never be eradicated.