【问题标题】:extern "C" Default argument works or not?extern "C" 默认参数是否有效?
【发布时间】:2018-11-07 00:43:15
【问题描述】:

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++。

【问题讨论】:

  • 我认为它有效,因为默认参数由调用者处理
  • extern "C" 并不表示“这是 C 代码”,它只影响导出符号的形式(即“方法”)。如果你将它提供给 C 编译器,它会同时抱怨 extern "C" 和默认参数。
  • 据我所知,当您尝试使用此导出时,您仍然需要提供 3 个参数。这是c++,所以你可以在这里提供默认参数,但是当你尝试使用导出的C函数时,你需要提供所有3个。
  • @Afshin "使用导出的 C 函数",你的意思是使用导出的 C 代码还是 C++ 代码?
  • @John 我的意思是当你想在 C 代码中使用导出的 C++ 代码时。

标签: c++ c arguments extern


【解决方案1】:

正如 molbdnilo 在 cmets 中已经指出的那样,extern "C" 并不意味着“这是 C 代码”,而是“这是带有 C 链接的代码”——即不会执行此函数的名称修改,因此您将能够使用“预期的”函数调用语法从 C 调用它。 C++ 编译器会修改函数的名称,因此它们可以支持函数重载,因为同一函数的不同重载的符号名称必须是唯一的(基本上,它们使用函数的范围、名称和参数类型来创建唯一的符号名称)。

根据[dcl.fct.default],标准的第1和2段:

如果 initializer-clauseparameter-declaration 中指定,则此 initializer-clause 用作默认参数。默认参数 将在缺少尾随参数的调用中使用。

[示例:声明

void point(int = 3, int = 4);

声明一个可以用零个、一个或两个类型的参数调用的函数 int。可以通过以下任何方式调用它:

point(1,2); point(1); point();

最后两个调用等价于point(1,4)point(3,4),分别。 — 结束示例 ]

此外,第 9 段规定:

默认参数不是函数类型的一部分。 [ 示例:

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

— 结束示例 ]

因此,对于带有默认参数 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 在 cmets 中已经提到的那样,这种实现方式使得无法将默认参数“传播”给共享库的其他用户,所以如果你想从 C 中使用它,你仍然需要将所有参数传递给函数。

【讨论】:

    猜你喜欢
    • 2019-12-22
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    • 2018-01-21
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多