errno实现机制困惑:宏定义与代码使用的矛盾疑问求助
解析
errno的实现逻辑:变量?宏?还是函数? 1. 先搞懂glibc里的errno宏到底是什么
你看到的#define errno (*__errno_location())不是把errno定义成函数,而是定义成一个可读写的int类型左值:
__errno_location()是个返回int*(整数指针)的函数,它会指向当前线程专属的errno变量- 对这个指针解引用后,就得到了真正的
int类型变量,所以errno = ERANGE展开后是(*__errno_location()) = ERANGE,这完全合法——本质是给指针指向的内存地址(也就是线程专属的int变量)赋值,不是给函数赋值。
2. 为什么strtol里会有extern int errno;?
这是兼容层的冗余声明:
- 有些老代码或者特殊编译场景下(比如手动
#undef errno关闭宏定义),需要直接使用全局的errno变量 - 但正常编译时,宏
errno会优先替换所有出现的errno标识符,所以这个声明不会和宏冲突,只是起到兜底作用。
3. 为什么要用这种宏实现,而不是直接用全局变量?
核心原因是线程安全:
- 如果
errno是全局变量,多线程环境下,一个线程设置的errno会被另一个线程的操作覆盖,导致错误信息混乱 - 通过
__errno_location()返回线程局部存储(TLS)的变量指针,每个线程都有自己独立的errno副本,操作互不干扰。
4. 苹果Unix实现里没有extern int errno;的原因
苹果的实现逻辑和glibc一致,都是用宏封装线程专属的errno,但它完全依赖宏来替代变量的使用,没有保留全局变量的兼容声明——因为宏已经覆盖了所有errno的使用场景,不需要再声明全局变量。
内容的提问来源于stack exchange,提问作者Amr Alasmer
相关产品推荐
相关产品推荐

