我正在尝试使用_Generic创建一个线程安全的strerror函数,该函数与使用strerror_r. XSI 变体返回一个int并修改传递给它的缓冲区的内容,而 GNU 版本返回一个char *.
strerror.c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "strerror.h"
static inline char *strerror_r_gnu(int errnum, char *buf, size_t buflen);
static inline char *strerror_r_xsi(int errnum, char *buf, size_t buflen);
static inline char *strerror_r_gnu(int errnum, char *buf, size_t buflen) {
// FUNKY CASTING TO SILENCE COMPILER WARNING BELOW
return (char *)(intptr_t)strerror_r(errnum, buf, buflen);
}
static inline char *strerror_r_xsi(int errnum, char *buf, size_t buflen) {
// Cast result to int to shut up compiler when using GNU strerror()
int err = (int)strerror_r(errnum, buf, buflen);
if (err) {
snprintf(buf, buflen, "%s error", __func__);
// If your buffer can't fit this error message, you deserve truncation
buf[buflen-1] = '\0';
}
return buf;
}
char *strerror_p(int errnum, char *buf, size_t buflen) {
return _Generic(strerror_r,
int (*)(int, char *, size_t) : strerror_r_xsi(errnum, buf, buflen),
char * (*)(int, char *, size_t) : strerror_r_gnu(errnum, buf, buflen)
);
}
Run Code Online (Sandbox Code Playgroud)
错误文件
#ifndef STRERROR_H
#define STRERROR_H
char *strerror_p(int errnum, char *buf, size_t buflen);
#endif // STRERROR_H
Run Code Online (Sandbox Code Playgroud)
主文件
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "strerror.h"
int main(void){
const int buflen = 128;
char buf[buflen]; // Flawfinder: ignore
fprintf(stderr, "%s\n", strerror_p(EINVAL, buf, buflen));
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
在strerror_r_gnu函数中,如果不强制转换 的结果strerror_r,编译器会incompatible integer to pointer conversion returning 'int' from a function with result type 'char *'在使用 XSI 版本的strerror_r. 由于在针对 的 XSI 版本编译时永远不会调用此函数strerror_r,因此我不关心类型不匹配,但我希望编译器对此保持沉默。强制转换到intptr_t然后到char *使编译器警告静音。
问题是,当使用strerror_r返回 a的 GNU 进行编译时,将char *结果强制转换为intptr_t和返回到的定义是否明确char *?
问题是,当使用返回 char * 的 GNU strerror_r 进行编译时,将结果转换
intptr_t为 char * 并返回到 char * 是否定义良好?
是的。这种操作的安全性几乎intptr_t是标准中的定义:
1 以下类型指定一个有符号整数类型,其属性为任何有效的指向 void 的指针都可以转换为该类型,然后转换回指向 void 的指针,结果将与原始指针相等:
Run Code Online (Sandbox Code Playgroud)intptr_t
(结合6.2.5p28:
指向 void 的指针应具有与指向字符类型的指针相同的表示和对齐要求。类似地,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求。所有指向结构类型的指针都应具有相同的表示和对齐要求。所有指向联合类型的指针都应具有相同的表示和对齐要求。指向其他类型的指针不需要具有相同的表示或对齐要求。
)