繁体   English   中英

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

[英]Using a C function from a C++ program - extern keyword problem

我在使用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 ++程序中?

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

extern "C" void squre_array();

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

#ifdef  __cplusplus
extern "C" {
#endif

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

#ifdef  __cplusplus
}
#endif

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

-皮特

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

第1步:
考虑片段1,它是C ++ int main()prog。 链接器将尝试执行您想要的操作,即使squre_array()可从main()访问(即可调用)。 在此C ++文件中,您必须#include 声明 squre_array()为C语言函数的头文件,这是整个过程中唯一的关键点 ,而不是C ++函数。 (为什么由于编译器格式和存储的C语言的符号不同于C ++符号;?,所以当接头出现时,在C源代码中定义的C型符号是不一样的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:


// 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

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

-皮特

考虑一下,我们有一个在Fh文件中声明的函数F(在Fc文件中定义)和一个main.cpp,其中F被包含并调用。 您的C编译器将Fh + Fc编译为目标文件Fo; 然后C ++编译器将Fh + main.cpp编译为main.o。 但是,C ++编译器会命名为mangling ,这意味着在Fh中声明的函数F将被编译器重命名为F_blah。 然后,链接器将尝试将main.o和Fo组合在一起:它将在main.o中找到对F_blah的调用,但找不到F_blah的主体,因为C编译器将其编译为F,而不是F_blah。 在这里,我们面临着无法解决的外部符号错误(VS中为LNK2001)。 对于这种情况,您需要告诉C ++编译器将函数名称保持不变:在.h文件中,您可以在以下代码块中声明该函数:

#ifdef  __cplusplus
extern "C" {
#endif

void F();

#ifdef  __cplusplus
}
#endif

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM