Last active
September 27, 2024 02:13
-
-
Save TheMatt2/414b3f0ad56cd231971361e68e8db8c2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// #include <stdio.h> | |
// #define XSTR(x) STR(x) | |
// #define STR(x) #x | |
// #pragma message "GLIBC " XSTR(__GLIBC__) "." XSTR(__GLIBC_MINOR__) | |
// strerror_.h | |
#ifndef STRERROR_H | |
#define STRERROR_H | |
/** | |
* @brief Portable thread safe strerror() | |
* | |
* A version of strerror() guaranteed to be thread safe | |
* and meant to be portable across multiple platforms. | |
* | |
* The returned string may be overwritten after future calls to strerror_() | |
* from the same thread. | |
* | |
* Thread safe. Not async safe. | |
* | |
* Behavior is undefined if locale is set to something other than LC_ALL. | |
* | |
* @param errnum Errno number to make a user generated string for. | |
* @returns Pointer to const string representing the error. | |
*/ | |
#if __STDC_VERSION__ >= 202311L | |
#define NO_DISCARD [[ nodiscard ]] | |
#elif defined(__GNUC__) | |
#define NO_DISCARD __attribute__ ((warn_unused_result)) | |
#else | |
#define NO_DISCARD /* nothing */ | |
#endif | |
NO_DISCARD const char* strerror_(int errnum); | |
#endif /* STRERROR_H */ | |
#include <errno.h> | |
#include <stdio.h> | |
#include <string.h> | |
/* strerror() is MT-safe for glibc >= 2.32 */ | |
#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32 | |
#ifndef HAS_STRERROR_MT_SAFE | |
#define HAS_STRERROR_MT_SAFE 1 | |
#endif | |
#endif /* glibc >= 2.32 */ | |
/* printf("%m") is defacto MT-safe for glibc >= 1.06 */ | |
#if __GLIBC__ >= 1 && __GLIBC_MINOR__ >= 6 | |
#ifndef HAS_PRINTF_M | |
#define HAS_PRINTF_M 1 | |
#endif | |
#endif /* glibc >= 1.06 */ | |
/* Define thread_local for thread specific buffer */ | |
#if __STDC_VERSION__ <= 199901L | |
#define thread_local __thread | |
#elif __STDC_VERSION__ < 202311L | |
// C23 changes thread_local to be a keyword | |
#define thread_local _Thread_local | |
#endif | |
#if HAS_STRERROR_MT_SAFE | |
// Just call strerror() when safe. | |
const char* strerror_(int errnum) | |
{ | |
return strerror(errnum); | |
} | |
#elif HAS_PRINTF_M | |
// Use printf("%m") to get errno string | |
// Pedantic warnings warns about usage of %m, but this code already checks | |
// %m is only used if available. | |
#ifdef __GNUC__ | |
#pragma GCC diagnostic push | |
#pragma GCC diagnostic ignored "-Wformat" | |
#endif /* __GNUC__ */ | |
const char* strerror_(int errnum) | |
{ | |
// Thread local buffer for errors. | |
// Longest EN error message on linux is EILSEQ is 49 characters + null. | |
static thread_local char errbuf[50] = {0}; | |
int prev_errno = errno; | |
errno = errnum; | |
snprintf(errbuf, sizeof(errbuf) - 1, "%m"); | |
errno = prev_errno; | |
return errbuf; | |
} | |
#ifdef __GNUC__ | |
#pragma GCC diagnostic pop | |
#endif /* __GNUC__ */ | |
#else | |
// POSIX General Solution. | |
#include <pthread.h> | |
const char* strerror_(int errnum) | |
{ | |
// Thread local buffer for errors. | |
// Longest EN error message on linux is EILSEQ is 49 characters + null. | |
static thread_local char errbuf[50] = {0}; | |
const char *buf; | |
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; | |
pthread_mutex_lock(&mutex); | |
// Call strerror() to get error status | |
buf = strerror(errnum); | |
// Copy to a thread specific buffer. Always leave null terminator. | |
buf = strncpy(errbuf, buf, sizeof(errbuf) - 1); | |
pthread_mutex_unlock(&mutex); | |
return buf; | |
} | |
#endif | |
int main(int argc, char *argv[]) | |
{ | |
(void) argc; | |
(void) argv; | |
printf(" (0): %s\n", strerror_(0)); | |
printf("EBADF : %s\n", strerror_(EBADF)); | |
printf("EILSEQ: %s\n", strerror_(EILSEQ)); | |
printf(" (999): %s\n", strerror_(999)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment