Windows x64调用约定下结构体处理的类型特性问询
返回值通过RAX传递的判断逻辑
你当前的CanBeReturnedInRAX概念存在冗余条件和边界遗漏,具体问题及修正方案如下:
问题点
- 冗余的
std::is_trivially_constructible_v<T>:MSVC x64调用约定对返回类型的默认构造函数无要求,只要类型可平凡拷贝(trivially copyable)且大小符合要求,即使默认构造非平凡,仍可通过RAX返回。该条件会错误排除此类合法类型。 - 冗余的
std::is_trivially_destructible_v<T>:std::is_trivially_copyable_v<T>已隐含析构函数平凡的要求,无需重复检测。 - 冗余的
std::is_standard_layout_v<T>:MSVC不要求返回类型是标准布局,例如带虚函数的类(非标准布局但平凡可拷贝、大小8字节)仍可通过RAX返回,该条件会错误排除此类情况。 - 不精确的大小限制:仅判断
sizeof(T) <=8会包含6、7字节的类型,而MSVC仅允许大小为1、2、4、8字节的平凡可拷贝类型通过RAX返回,6/7字节的类型需调用者分配缓冲区并通过地址传递。
修正后的概念
template <typename T> concept CanBeReturnedInRAX = std::is_trivially_copyable_v<T> && (sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
边界情况验证
- 带虚函数的平凡可拷贝类(如
struct A { virtual void f(); }):大小8字节,符合条件,可通过RAX返回。 - 有非平凡默认构造但平凡拷贝的类:如
struct S { S() { /* 非平凡逻辑 */ } S(const S&) = default; int x; },大小4字节,符合条件,可通过RAX返回。 - 6字节的平凡可拷贝结构体:如
struct S { char data[6]; },被正确排除,需通过地址返回。
参数通过寄存器传递的判断逻辑
MSVC x64调用约定中,参数能否通过寄存器传递的核心依据是类型是否平凡可拷贝以及大小是否为1、2、4、8、16字节,具体规则如下:
可通过寄存器传递的条件
类型需同时满足:
std::is_trivially_copyable_v<T>为true(无自定义拷贝/移动构造、赋值操作,析构函数平凡);- 大小为1、2、4、8或16字节。
对应的概念实现:
template <typename T> concept CanBePassedInRegisters = std::is_trivially_copyable_v<T> && (sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8 || sizeof(T) == 16);
关键细节说明
- 16字节类型:会占用两个通用寄存器(如
RCX+RDX)传递,例如struct S { long long a; long long b; }这类16字节的平凡可拷贝结构体。 - 非平凡可拷贝类型:无论大小如何,均需通过地址传递(调用者分配栈空间,传递指针到寄存器),例如带自定义拷贝构造函数的类。
- 私有成员的类:只要类是平凡可拷贝的(如默认拷贝构造、析构),即使包含私有成员,仍可通过寄存器传递。
- 数组类型:数组的处理等价于其元素组成的连续内存块,例如
int arr[2](大小8字节,平凡可拷贝)可通过寄存器传递,int arr[3](大小12字节)则需地址传递。
内容的提问来源于stack exchange,提问作者Juliean
相关产品推荐
相关产品推荐

