我试图了解 glibc 如何在没有预处理器替换errno
符号的情况下初始化errno
。
我首先尝试根据csu/errno-loc.c和csu/errno.c自行实现一个简单版本:
myerrno.h
#ifndef MYERRNO_H
#define MYERRNO_H
extern int *myerrno_location(void);
#define myerrno (*myerrno_location())
#endif
myerrno.c
#include "myerrno.h"
static int myerrno = 0;
int *myerrno_location(void){
return &myerrno;
}
但是,当我尝试编译时,收到以下错误消息:
myerrno.c:3:1: error: function ‘myerrno_location’ is initialized like a variable
myerrno.c:3:12: error: static declaration of ‘myerrno_location’ follows non-static declaration
myerrno.h:4:13: note: previous declaration of ‘myerrno_location’ was here
我可以说,预处理器在第3行遇到(*myerrno_location(void))
时会替换myerrno
- 自然这是预期的行为。
我不明白为什么这对 glibc 来说不是问题。 errno
的线程安全实现如何解决这个预处理器替换问题而不重命名静态errno
变量?
答案 0 :(得分:3)
修复问题就像更改静态变量的名称一样简单。
static int myerrno_variable = 0;
int *myerrno_location(void){
return &myerrno_variable;
}
请注意,由于所有线程都访问相同的myerrno_variable
,因此您的版本仍然不是线程安全的。真正的实现将返回特定于线程的内存位置。在GCC中,有一个提供__thread
存储类的扩展。 C.11提供了自己的版本,称为thread_local
,但只有在实现提供线程支持时才可用(可以通过查看是否定义了__STDC_NO_THREADS__
来检查)。
static __thread int myerrno_variable_gcc; /* if using GCC */
static thread_local int my_errno_variable_c11; /* if __STD_NO_THREADS__ isn't defined */
在没有线程本地功能的POSIX系统上,实现可以使用pthread_getspecific()
来获取指向为每个线程分配的线程特定数据的指针,并使用pthread_setspecific()
进行设置。有关详细信息,请参阅the manual。