使用C ++程序中的C函数 - extern关键字问题

时间:2011-03-16 05:54:34

标签: c extern

我遇到了C ++程序的问题。我想使用在C ++文件中的C文件中定义的函数。这是我的C ++文件代码:

#include <string>
#include <iostream>
#include <stdio.h>
extern void squre_array();
using namespace std;

int main() {
    squre_array();
}

现在这里是我定义squre_array()

的C文件的代码
#include <stdio.h>
#include <cuda.h>

__global__ void square_array(float *a, int N)
{
  int idx = blockIdx.x * blockDim.x + threadIdx.x;
  if (idx<N) 
    a[idx] = a[idx] * a[idx];
}
void squre_array()
{
  float *a_h, *a_d; 
  const int N = 10;  
  size_t size = N * sizeof(float);
  a_h = (float *)malloc(size);        
  cudaMalloc((void **) &a_d, size);   
  for (int i=0; i<N; i++) a_h[i] = (float)i;
  cudaMemcpy(a_d, a_h, size, cudaMemcpyHostToDevice);
  int block_size = 4;
  int n_blocks = N/block_size + (N%block_size == 0 ? 0:1);
  square_array <<< n_blocks, block_size >>> (a_d, N);

  cudaMemcpy(a_h, a_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
  // Print results
  for (int i=0; i<N; i++) printf("%d %f\n", i, a_h[i]);

  free(a_h); 
  cudaFree(a_d);
}

现在可以告诉我如何将此功能链接到我的C ++程序吗? 每次编译程序时,都会收到错误消息:

cpp:: undefined reference to `squre_array()'

谁能告诉我我做错了什么? 如何将squre_array()函数链接到我的C ++程序?

4 个答案:

答案 0 :(得分:6)

在C ++代码中,您需要将C函数声明为extern“C”

extern "C" void squre_array();

答案 1 :(得分:3)

在代码段的第一行之前,添加以下三行:

#ifdef  __cplusplus
extern "C" {
#endif

在代码段的最后一行之后,添加以下三行:

#ifdef  __cplusplus
}
#endif

魔术?不,只有C和C ++编译器以不同的格式保存代码的符号;这使得C ++链接器可以理解代码片段中的C符号。

- 皮特

答案 2 :(得分:2)

在OP应用了一些编辑之后,我们一步一步地修改现在的OP代码(3月17日东部0600):

步骤1:
考虑片段1,这是C ++ int main()prog。链接器将尝试执行您想要的操作,即使main()可以访问squre_array(),即可调用。在此C ++文件中,您必须#include 声明 squre_array()的头文件为 C语言 function - 整个过程中唯一的 关键点 - 而不是C ++函数。 (为什么?因为编译器格式化和存储C语言符号与C ++符号不同;因此当链接器出现时,C源中定义的C类型符号 不一样 作为main()中引用的C ++类型符号。)现在,该头文件名为cuda.h吗?我们假设它是。请记住,这样的声明会使“extern void squre_array()”变得多余和令人困惑,因此请从该源文件中取出该行:

#include <string>
#include <iostream>
#include <stdio.h>
#include <cuda.h>         <-- add this line
//extern void squre_array();  <-- delete this line: we'll declare squre_array( ) in cuda.h
using namespace std;

int main() { squre_array(); }

步骤2:
现在考虑片段2, 定义 squre_array()函数。这是普通的旧C代码,因此我们必须将所有C代码括起来,每组包含两组三行。这六行(总计)有效地告诉链接器括号中的符号是C型符号而不是C ++ - 类型“munged”符号。当链接器最终确信它时,它可以将squre_array()函数链接到主程序中:

// insert magic three lines here, way up at the top of your .c file
#ifdef __cplusplus //if we are compiling as C++, tell
extern "C" { //the compiler that this stuff is plain old C
#endif

#include <stdio.h>
#include <cuda.h> <-- remember this "glue" file: we'll change it in step 3

//_global_ void square_array(float *a, int N) <-- remove the declaration,
void square_array(float *a, int N) { <-- but retain the definition

int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx a[idx] = a[idx] * a[idx];
}
void squre_array()
{
float *a_h, *a_d;
...
cudaFree(a_d);
}
// close magic three lines
#ifdef __cplusplus //
} // closing curly bracket
#endif

STEP 3:
The important thing that is missing from the OP's understanding is that squre_array( ) (and square_array( ), if you want) must be declared; and that declaration(s) need to be enclosed within the same pair of magic three lines. (OP: why must that be?) We decided in step 1 that the declaration would go in cuda.h. Or it can go in any .h file, but wherever it's declared, that .h file has to be #included in the file where main( ) resides (OP: again, why is this?). So let's fix up cuda.h:

// magic three lines again
#ifdef __cplusplus
extern "C" {
#endif
void squre_array();
void square_array(float *a, int N);
// close magic three lines, just like before
#ifdef __cplusplus //
} // closing curly bracket
#endif

就是这样。现在您的程序将链接。

- 皮特

答案 3 :(得分:0)

考虑我们在F.h文件中声明了一个函数F,它在F.c文件和main.cpp中定义,其中F是#included并被调用。您的C编译器将F.h + F.c编译为目标文件F.o;然后C ++编译器将F.h + main.cpp编译为main.o.但是,C ++编译器执行name mangling,这意味着在F.h中声明的函数F将被编译器重命名为例如F_blah。然后链接器会尝试组合main.o和F.o:它会在main.o中找到对F_blah的调用,但它找不到F_blah的主体,因为C编译器将其编译为F,而不是F_blah。在这里,我们处理未解决的外部符号错误(VS中的LNK2001)。对于这样的情况,你需要告诉C ++编译器保持函数的名称:在.h文件中,你在下面的块中声明了这样的函数:

#ifdef  __cplusplus
extern "C" {
#endif

void F();

#ifdef  __cplusplus
}
#endif