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 中使用它,你'仍然需要将所有参数传递给函数。