将指针投射到 intptr_t 并返回
Casting pointer to intptr_t and back
我正在尝试使用 _Generic
制作一个线程安全的 strerror
函数,该函数与使用 strerror_r
的 XSI 或 GNU 变体无关。 XSI 变体 returns 和 int
并修改传递给它的缓冲区的内容,而 GNU 版本 returns 和 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] = '[=11=]';
}
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)
);
}
strerror.h
#ifndef STRERROR_H
#define STRERROR_H
char *strerror_p(int errnum, char *buf, size_t buflen);
#endif // STRERROR_H
main.c
#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;
}
在strerror_r_gnu
函数中,如果不强制转换strerror_r
的结果,编译器在用strerror_r
的XSI版本编译时会吐出一个警告incompatible integer to pointer conversion returning 'int' from a function with result type 'char *'
。由于此函数在针对 strerror_r
的 XSI 版本编译时永远不会被调用,我不关心类型不匹配,但我希望编译器对此保持沉默。转换为 intptr_t
,然后转换为 char *
会使编译器警告静音。
问题是,当用 GNU strerror_r
编译时 returns 一个 char *
,将结果转换为 intptr_t
并返回到char *
?
The question is, when compiling with the GNU strerror_r that returns a
char *, is it well-defined to cast the result to intptr_t
and back to
char *?
是的。这种操作的安全性几乎就是标准中intptr_t
的定义:
7.20.1.4 Integer types capable of holding object pointers
1 The following type designates a signed integer type with the
property that any valid pointer to void can be converted to this type,
then converted back to pointer to void, and the result will compare
equal to the original pointer:
intptr_t
(将其与 6.2.5p28 合并:
A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of compatible
types shall have the same representation and alignment requirements.
All pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types
shall have the same representation and alignment requirements as each
other. Pointers to other types need not have the same representation
or alignment requirements.
)
我正在尝试使用 _Generic
制作一个线程安全的 strerror
函数,该函数与使用 strerror_r
的 XSI 或 GNU 变体无关。 XSI 变体 returns 和 int
并修改传递给它的缓冲区的内容,而 GNU 版本 returns 和 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] = '[=11=]';
}
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)
);
}
strerror.h
#ifndef STRERROR_H
#define STRERROR_H
char *strerror_p(int errnum, char *buf, size_t buflen);
#endif // STRERROR_H
main.c
#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;
}
在strerror_r_gnu
函数中,如果不强制转换strerror_r
的结果,编译器在用strerror_r
的XSI版本编译时会吐出一个警告incompatible integer to pointer conversion returning 'int' from a function with result type 'char *'
。由于此函数在针对 strerror_r
的 XSI 版本编译时永远不会被调用,我不关心类型不匹配,但我希望编译器对此保持沉默。转换为 intptr_t
,然后转换为 char *
会使编译器警告静音。
问题是,当用 GNU strerror_r
编译时 returns 一个 char *
,将结果转换为 intptr_t
并返回到char *
?
The question is, when compiling with the GNU strerror_r that returns a char *, is it well-defined to cast the result to
intptr_t
and back to char *?
是的。这种操作的安全性几乎就是标准中intptr_t
的定义:
7.20.1.4 Integer types capable of holding object pointers
1 The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:
intptr_t
(将其与 6.2.5p28 合并:
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.
)