外部"C"默认参数有效吗? [英] extern "C" Default argument works or not?

查看:74
本文介绍了外部"C"默认参数有效吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此处看来,C不支持默认参数.

我在导出的库中具有以下方法:

 外部"C"{__declspec(dllexport)uintptr_t方法(int freq,int * pRetval,bool * support2MHz);} 

如果我使最后一个参数像这样可选:

 外部"C"{__declspec(dllexport)uintptr_t方法(int freq,int * pRetval,bool * support2MHz = NULL);} 

我的dll仍在编译.我的问题是为什么??每个人都说C代码不支持默认参数.

我将C ++用于MS 2015.

解决方案

正如molbdnilo在评论中已经指出的那样, extern"C" 并不意味着这是C代码",而是这是带有C链接的代码"-即不会执行此函数的名称修改,因此您可以使用期望的"函数调用语法从C调用它.C ++编译器会对函数名称进行修饰,以便它们可以支持函数重载,因为同一函数的不同重载的符号名必须是唯一的(基本上,它们使用函数的作用域,名称和参数类型来创建唯一的符号名).

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

如果在 parameter-declaration 中指定了初始化器子句,则 initializer-clause 用作默认参数.默认参数将用于缺少尾随参数的调用中.

[示例:声明

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

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

  point(1,2);点(1);观点(); 

最后两个调用等效于 point(1,4)和分别是 point(3,4).—示例]

此外,第9段指定:

默认参数不属于函数类型.[示例:

  int f(int = 0);无效h(){int j = f(1);int k = f();//OK,表示f(0)}int(* p1)(int)=& f;int(* p2)()=& f;//错误:类型不匹配 

-示例]

因此,对于具有默认参数 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链接的符号,因此不会发生名称冲突.

您可以在Godabolt上的实时示例中看到各种编译器的行为.

但是,正如Afshin在评论中已经提到的那样,实现该方法的方式使得不可能将默认参数传播"给共享库的其他用户,因此,如果您想从C使用它,您仍然需要将所有参数传递给函数.

From Here it seems that default argument are not supported by C.

I have the following method in exported library:

extern "C" 
{
    __declspec (dllexport) uintptr_t Method(int freq, int *pRetval, bool *support2MHz);
}

If i made last argument optional like this:

extern "C" 
{
    __declspec (dllexport) uintptr_t Method(int freq, int *pRetval, bool *support2MHz = NULL);
}

My dll is still compiled. My question is why? Everyone says the default arguments are not supported in C code.

I use C++ for MS 2015.

解决方案

As molbdnilo already noted in the comments, extern "C" does not mean "this is C code", but "this is code with C linkage" - i.e. name mangling for this function will not be performed, so you will be able to call it from C with the "expected" function call syntax. C++ compilers mangle the names of functions so they can support function overloading, since symbol names of different overloads of the same function have to be unique (basically, they use function's scope, name and argument types to create a unique symbol name).

According to [dcl.fct.default], paragraphs 1 and 2 of the standard:

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 ]

In addition, paragraph 9 specifies:

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 ]

Thus, for a function with a default argument int foo(int x, int y = 0), the compiler will not generate two overloads (int foo(int x, int y) and int foo(int x), with y fixed to 0), but instead replace every call of the form foo(x) with a call to foo(x, 0). In your concrete example with extern "C" this means that the compiler generates only one symbol with C linkage for Method so there is no name clash.

You can see this behavior for various compilers in a live example on godbolt.

However, as Afshin already mentioned in the comments, the way this is implemented makes it impossible to "propagate" default arguments to other users of your shared library, so if you want to use this from C, you'll still need to pass all arguments to the function.

这篇关于外部"C"默认参数有效吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆