外部“C”是否应包含C ++函数的声明或定义?

时间:2016-06-20 16:23:02

标签: c++ c

我在cpp文件中看到ts = datetime.datetime.now() cursor.prepare("INSERT INTO python_tstamps VALUES(:t_val)") cursor.setinputsizes(t_val=cx_Oracle.TIMESTAMP) cursor.execute(None, {'t_val':ts}) db.commit() 包含了几个函数的定义。

https://isocpp.org/wiki/faq/mixing-c-and-cpp开始,我想在cpp文件中使用external "C" {...}的目的是使附带的C ++函数可用于C程序。

链接中的示例显示extern "C"仅包含C ++函数的声明,而不是它们的定义

  

只需声明C ++函数extern“C”(在您的C ++代码中)并调用   它(来自您的C或C ++代码)。例如:

extern "C"

我在开头提到的cpp文件看起来像:

    // C++ code:
    extern "C" void f(int);
    void f(int i)
    {
        // ...
    }

应该{​​{1}}包含C ++函数的声明或定义吗? 如果是这样,为什么?

5 个答案:

答案 0 :(得分:15)

它应该将声明括在头文件中,并且只要使用c ++编译器编译转换单元就应该包含定义,并且只要在那里看不到声明。
在c ++代码中做两件事都没有错。

如果c编译器用于编译函数定义,则没有必要(或者我应该更好地说语法错误,请参阅下面的注释)。

extern "C" {}范围控制普通c符号链接用于内部的所有内容。否则c++ name mangling将被应用。

注意:

由于extern "C" {}这不是有效的c语法,为了使其与c编译器一起使用,您需要在#ifdef中使用它:

<强> MyHeader.h

 #ifdef __cplusplus
 extern "C" {
 #endif

 // ... c style function name declarations
 void foo(int i);

 #ifdef __cplusplus
 } // extern "C"
 #endif

使用extern "C" {}范围实际上是双重的:

将C ++代码导出到C

如果使用c编译器编译上述内容,则会将其显示为普通的c函数声明。如果使用c ++编译器编译,则应用extern关键字,并且将禁止c ++名称修改。

关于定义,该函数可以使用其定义中的任何c ++特性:

 extern "C" {
     void foo(int x) {
         std::vector v(x);
         // ... blah, more c++ stuff
     }
 }

请注意,此处未包含声明。这可以用作一种技术,当您想要覆盖从weak linkage库中公开的函数时,它尤其有用。

如果包含MyHeader.h,则extern "C" {}范围可以省略。

从C ++导入C代码

如果在c ++编译器中看到上述声明,则再次禁止c ++名称修改,并且链接器将使用普通c函数符号名称解析对foo()的任何调用引用:

  #include "MyHeader.h"
  class MyClass {
  public:
       void bar(int y) {
           // Use foo() as plain c function:
           foo(y);
       }
  };

foo()函数实现是使用c编译器创建的目标文件(或归档文件)提供的。

答案 1 :(得分:7)

[dcl.link] / 5:

  

除了具有C ++链接的函数,没有函数声明   链接规范不应在第一个链接之前   该功能的规范。可以在没有a的情况下声明函数   已经明确的链接规范之后的链接规范   可见;前面声明中明确指定的链接是   不受这种功能声明的影响。

就功能的语言链接而言,两个版本都很好。重要的是,函数的第一个声明必须有extern "C"

答案 2 :(得分:3)

最好包括两者。

当我们在C ++中链接C代码时,确保符号没有被破坏。我们使用extern&#34; C&#34;块。

每当将某些代码放在extern“C”块中时,C ++编译器就会确保函数名称是无符号的,即编译器生成一个二进制文件,其名称不变,就像C编译器一样。

Mangling由于C ++支持函数重载,所以基本上可以有多个具有相同名称的函数。因此,在生成目标代码时要区分不同的函数 - 它通过添加有关参数的信息来更改名称。向函数名添加附加信息的技术称为Name Mangling。

由于C不支持函数重载。所以我们使用extern&#39; C&#39;在C ++中链接C代码时阻塞。

答案 3 :(得分:1)

您应该包含声明和定义。 &#34; C&#34;和&#34; C ++&#34;函数以不同的名称导出。为了产生正确的&#34; C&#34; cpp中需要对象文件matcher.matches()中的外部名称,否则将使用C++ name mangling导出函数。您还需要将那些extern "C"和相应的extern "C" {括在头文件中的}#ifdef __cplusplus中,这将被C项目#included以避免C编译错误

答案 4 :(得分:-2)

same document中,它显示了一个代码示例,该示例在声明中有For i = ActiveChart.SeriesCollection.Count To 1 Step -1 If ActiveChart.Legend(i)= "Test: *" Then ActiveChart.Legend(i) **what I think needs to be modified** End If Next i ,但在定义中没有。

如果您的定义&#34;看到&#34;声明(即声明在翻译单元中的定义之前),您需要extern "C"定义。但它不会受到伤害 - 编译器会默默地忽略它。

这是FAQ中给出的代码示例:

extern "C"

如果您出于任何原因决定不在定义之前加入声明,则必须提供// This is C++ code // Declare f(int,char,float) using extern "C": extern "C" void f(int i, char c, float x); // ... // Define f(int,char,float) in some C++ module: void f(int i, char c, float x) { // ... } 修饰符:

extern "C"

然而,这违背了C和C ++的大多数风格指南。