You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MSVC中_setjmp的定义、链接匹配机制及相关疑问

MSVC中_setjmp的定义、链接匹配机制及相关疑问

这个问题确实戳中了MSVC与统一C运行时库(ucrtbase.dll)交互里比较隐晦的实现细节,我来一步步拆解清楚:

一、先确认你观察到的符号差异

首先你通过objdump查到的两个ucrtbase.dll里的setjmp相关符号差异是准确的:

SysWOW64(32位ucrtbase)的符号:

C:\Users\_____\Desktop\b>objdump -x C:\Windows\SysWOW64\ucrtbase.dll | findstr setjmp
[  88] +base[  89] 0058 __intrinsic_setjmp
[1860] +base[1861] 0744 _setjmp3

System32(64位ucrtbase)的符号:

C:\Users\_____\Desktop\b>objdump -x C:\Windows\System32\ucrtbase.dll | findstr setjmp
[  74] +base[  75] 004a __intrinsic_setjmp
[  75] +base[  76] 004b __intrinsic_setjmpex
[2370] +base[2371] 0942 setjmp

二、MSVC头文件的定义逻辑

在MSVC的头文件(比如你用的2019 BuildTools版本)里,setjmp被宏替换为_setjmp,同时声明了对应的函数原型:

#ifndef _INC_SETJMPEX
#define setjmp _setjmp
#endif

// Function prototypes
int __cdecl setjmp( _Out_ jmp_buf _Buf );

这里的矛盾点很明显:所有setjmp都被替换成_setjmp,但_setjmp的符号在两个ucrtbase.dll里都找不到,编辑器也搜不到它的函数定义——这也是你疑惑的核心。

三、对比mingw-w64的处理方式

先看mingw-w64的实现,它是明着根据架构切换函数的:

x86(32位):

#define setjmp(BUF) _setjmp3((BUF), NULL)
...
int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp3(jmp_buf _Buf, void *_Ctx);

直接把setjmp映射到_setjmp3,手动传NULL作为上下文参数。

x64(64位):

#define _setjmp __intrinsic_setjmpex
...
#define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0))
...
int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp(jmp_buf _Buf, void *_Ctx);

通过多层宏,最终把setjmp映射到未公开的__intrinsic_setjmpex,同时自动获取栈帧地址作为上下文参数。

四、MSVC的核心实现逻辑:_setjmp是编译器处理的特殊内在函数

你的猜测完全正确:MSVC里的_setjmp确实是文档未公开的编译器内在函数(intrinsic),它的工作机制是:

  • 当你在代码中使用setjmp(被宏替换为_setjmp)时,MSVC编译器不会把它当成普通的外部函数符号去ucrtbase里查找链接,而是会根据目标架构直接做以下处理:
    1. x86(32位)程序:编译器自动把_setjmp的调用转换成对ucrtbase里_setjmp3的调用,同时隐式传入NULL作为上下文参数(和mingw-w64的逻辑一致)。
    2. x64(64位)程序:编译器自动把_setjmp的调用转换成对ucrtbase里__intrinsic_setjmpex或setjmp的调用,同时自动生成获取栈帧地址的代码作为上下文参数。
  • 你提到msvcrt.dll里有_setjmp,但那是旧版CRT的符号,现在MSVC默认链接的ucrtbase是统一CRT,确实没有导出_setjmp——但编译器通过内在函数机制绕开了普通的符号查找流程,直接生成适配目标架构的机器码和函数调用。
  • 至于为什么它是“未公开”的?因为微软只把对外推荐使用的intrinsic函数列在官方文档里,这类和CRT深度绑定的实现细节函数,一般不会对外文档化,属于编译器和CRT的私有约定。

总结

MSVC的这套设计是为了给开发者提供统一的setjmp接口,不用关心底层架构的差异:头文件用宏把setjmp统一替换成_setjmp,编译器再把_setjmp这个“伪符号”转换成对应架构下ucrtbase里实际存在的函数调用,全程不需要开发者手动处理参数或切换函数名——这就是为什么你看不到_setjmp的定义,程序却能正常链接运行的原因。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 10:39:36