什么是保留参数(reserved parameter)
某些 API 函数的部分参数要求调用者必须传入指定的固定值,且这些参数名中通常带 reserved 字样。一般来说,调用者不遵守此约定会导致调用失败。
例如,Windows API 中的:
LONG WINAPI RegQueryValueEx(
__in HKEY hKey,
__in_opt LPCTSTR lpValueName,
__reserved LPDWORD lpReserved,
__out_opt LPDWORD lpType,
__out_opt LPBYTE lpData,
__inout_opt LPDWORD lpcbData
);
这里的 lpReserved 必须传 NULL,不然调用失败。
为什么要有保留参数
主要原因有两个。
一是方便扩展,且扩展不改变 ABI。如果没有保留参数,那么扩展函数功能必须另外取名(提供一个新函数),例如 accept2
、accept3
、accept4
这样很丑的名字。
二是供内部调用使用。例如,用户态程序调用必须传指定值,而系统内部可以使用这个值达成某种目的。
还有一种说法是这个参数之前有用,现已废弃。我认为可能性不大,如果要求废弃的参数必须传指定值,那么旧程序就会失效。
什么时候设计保留参数
需要 ABI 长期兼容且有比较大概率需要扩展的场景可以考虑使用保留参数。
反之,不需要 ABI 兼容的场景或已经确定无扩展需要的场景不应使用保留参数。用了反而给调用者和库作者带来必须要的干扰。
以下情况不应使用保留参数:
- HTTP API,增加参数之后客户端不用修改,只要在服务端处理默认值。
- 私有库,需要扩展时,双方都改。
- 参数已彻底设计好。
- 短期产品或项目。
怎样设计保留参数
(1)切勿滥用。
(2)保留参数一般放在最后一个。
(3)保留参数的类型要适应尽可能多的情况。例如,C 语言库的保留参数类型一般为 void*
,将来可以改成任何指针类型。