As everybody knows, C allows us to write anything we want. There comes one big problem — we are the only who responsible to handle errors that comes from standard library functions and, therefore, write reliable code.
The goal is to make writing reliable code easier.
And the question is about errors that comes from standard library functuins.
I have an idea to wrap standard functions so that we can’t hide errors. If we want to ignore errors, we’ll need to explicitly do that.
This code shows my solution:
void
safe_access
(bool *ok, const char *path, int amode)
{
// reset error
*ok = true;
errno = 0;
int ret = access(path, amode);
// indicate error
if (ret) {
*ok = false;
}
}
This functuon wraps access(3) from unistd.h. It solves the followind three problems:
- It resets errno, so we won’t be able to check for old errno:
// this function sets errno
access(...);
// we forget to reset errno and everything seems to be OK
// now, we want to check for errno
// but, unfortunately, we’re prone to check old errno that comes from access()
long a = strtol(...);
if (... && errno) {
}
- It disallows us to forget handling errors. Even when we want to ignore errors, we need to explicitly do that:
bool ok;
safe_access(&ok, ...);
// we need something to do with `ok`
Also, we can tune warnings to disallow us to keep variables unused.
- Everybody will check errors the same way. This is not regular but sometimes we need to check errors differently than just if-not-zero, if-negative, or if-NULL. For example, we need to use
ferror(3)
afterfread(3)
. My solution is to writesafe_fread()
that will do it.
Are there any risks and what are they?
malloc(3)
,fopen(3)
,access(3)
,stat(3)
, etc) set errno to indicate errors. The scope is global, @candied_orangeerrno
is sometimes needed for disambiguation. It is only cleared if (potentially) needed for disambiguation or manually, and set if an error occurred.