extern "C" 默认参数是否有效?
extern "C" Default argument works or not?
从 Here 看来,C 不支持默认参数。
我在导出库中有以下方法:
extern "C"
{
__declspec (dllexport) uintptr_t Method(int freq, int *pRetval, bool *support2MHz);
}
如果我像这样将最后一个参数设为可选:
extern "C"
{
__declspec (dllexport) uintptr_t Method(int freq, int *pRetval, bool *support2MHz = NULL);
}
我的dll还在编译中。 我的问题是为什么?每个人都说 C 代码不支持默认参数。
我在 MS 2015 中使用 C++。
正如 molbdnilo 已经在评论中指出的那样,extern "C"
并不意味着 "this is C code",而是 "this is code with C linkage" - 即不会执行此功能的名称修改,因此您将能够使用 "expected" 函数调用语法从 C 中调用它。 C++ 编译器会破坏函数的名称,以便它们可以支持函数重载,因为同一函数的不同重载的符号名称必须是唯一的(基本上,它们使用函数的作用域、名称和参数类型来创建唯一的符号名称)。
根据[dcl.fct.default],标准第 1 段和第 2 段:
If an initializer-clause is specified in a parameter-declaration this
initializer-clause is used as a default argument. Default arguments
will be used in calls where trailing arguments are missing.
[Example: The declaration
void point(int = 3, int = 4);
declares a function that can be called with zero, one, or two arguments of type
int
. It can be called in any of these ways:
point(1,2); point(1); point();
The last two calls are equivalent to point(1,4)
and
point(3,4)
, respectively. — end example ]
此外,第 9 段规定:
A default argument is not part of the type of a function. [ Example:
int f(int = 0);
void h() {
int j = f(1);
int k = f(); // OK, means f(0)
}
int (*p1)(int) = &f;
int (*p2)() = &f; // error: type mismatch
— end example ]
因此,对于具有默认参数int foo(int x, int y = 0)
的函数,编译器不会生成两个重载(int foo(int x, int y)
和int foo(int x)
,y
固定为0
),而是将 foo(x)
形式的每个调用替换为对 foo(x, 0)
的调用。在您使用 extern "C"
的具体示例中,这意味着编译器只为 Method
生成一个带有 C 链接的符号,因此没有名称冲突。
您可以在 live example on godbolt.
中看到各种编译器的这种行为
然而,正如 Afshin 已经在评论中提到的那样,这种实现方式使得无法 "propagate" 默认参数给共享库的其他用户,所以如果你想从 C 中使用它,你'仍然需要将所有参数传递给函数。
从 Here 看来,C 不支持默认参数。
我在导出库中有以下方法:
extern "C"
{
__declspec (dllexport) uintptr_t Method(int freq, int *pRetval, bool *support2MHz);
}
如果我像这样将最后一个参数设为可选:
extern "C"
{
__declspec (dllexport) uintptr_t Method(int freq, int *pRetval, bool *support2MHz = NULL);
}
我的dll还在编译中。 我的问题是为什么?每个人都说 C 代码不支持默认参数。
我在 MS 2015 中使用 C++。
正如 molbdnilo 已经在评论中指出的那样,extern "C"
并不意味着 "this is C code",而是 "this is code with C linkage" - 即不会执行此功能的名称修改,因此您将能够使用 "expected" 函数调用语法从 C 中调用它。 C++ 编译器会破坏函数的名称,以便它们可以支持函数重载,因为同一函数的不同重载的符号名称必须是唯一的(基本上,它们使用函数的作用域、名称和参数类型来创建唯一的符号名称)。
根据[dcl.fct.default],标准第 1 段和第 2 段:
If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument. Default arguments will be used in calls where trailing arguments are missing.
[Example: The declaration
void point(int = 3, int = 4);
declares a function that can be called with zero, one, or two arguments of type
int
. It can be called in any of these ways:point(1,2); point(1); point();
The last two calls are equivalent to
point(1,4)
andpoint(3,4)
, respectively. — end example ]
此外,第 9 段规定:
A default argument is not part of the type of a function. [ Example:
int f(int = 0); void h() { int j = f(1); int k = f(); // OK, means f(0) } int (*p1)(int) = &f; int (*p2)() = &f; // error: type mismatch
— end example ]
因此,对于具有默认参数int foo(int x, int y = 0)
的函数,编译器不会生成两个重载(int foo(int x, int y)
和int foo(int x)
,y
固定为0
),而是将 foo(x)
形式的每个调用替换为对 foo(x, 0)
的调用。在您使用 extern "C"
的具体示例中,这意味着编译器只为 Method
生成一个带有 C 链接的符号,因此没有名称冲突。
您可以在 live example on godbolt.
中看到各种编译器的这种行为然而,正如 Afshin 已经在评论中提到的那样,这种实现方式使得无法 "propagate" 默认参数给共享库的其他用户,所以如果你想从 C 中使用它,你'仍然需要将所有参数传递给函数。