Использование функции C из программы на C ++ - проблема с ключевым словом extern - PullRequest
1 голос
/ 16 марта 2011

У меня проблема с программой на C ++. Я хочу использовать функцию, которая определена в файле C в файле C ++. Вот мой код для файла C ++:

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

int main() {
    squre_array();
}

Теперь вот код для файла C, в котором я определил squre_array():

#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 ]

6 голосов
/ 16 марта 2011

В коде C ++ вам нужно объявить функцию C как внешнюю "C"

extern "C" void squre_array();
3 голосов
/ 16 марта 2011

Перед первой строкой своего кода добавьте три строки: &#35;ifdef __cplusplus extern "C" { &#35;endif

После последней строки вашего фрагмента кода добавьте три строки: &#35;ifdef __cplusplus } &#35;endif

Магия? Нет, только компиляторы C и C ++ сохраняют символы вашего кода в разных форматах; это позволяет компоновщику C ++ понимать символы C в вашем фрагменте кода.

- * Пита 1009 *

2 голосов
/ 17 марта 2011

Шаг за шагом, давайте изменим код OP, как он появляется сейчас (17 марта в 06:00 восточнее), после того, как OP применил несколько правок:

ШАГ 1:
Рассмотрим фрагмент 1,которая является прогой C ++ int main ().Компоновщик попытается сделать то, что вы хотите, то есть сделать squre_array () доступным - то есть вызываемым - из main ().В этом файле C ++ вы должны #include заголовочный файл, который объявляет squre_array () как язык C функция -единственная критическая точка во всем этом процессе, а не функция C ++.(Почему? Поскольку компилятор форматирует и хранит символы языка C по-другому, чем символы C ++; и поэтому, когда появляется компоновщик, символ типа C, определенный в источнике C, имеет вид , а не тот же как символ типа C ++, указанный в main ().) Теперь этот заголовочный файл называется cuda.h?Давайте предположим, что это так.Помните, что такое объявление делает "extern void squre_array ()" излишним и запутанным, поэтому уберите эту строку из этого исходного файла: &#35;include <string> &#35;include <iostream> &#35;include <stdio.h> <strong>&#35;include <cuda.h> <-- add this line</strong> //extern void squre_array(); <strong><-- delete this line: we'll declare squre_array( ) in cuda.h</strong> using namespace std;</p> <p>int main() { squre_array(); } STEP 2:
Теперь рассмотрим фрагмент 2, который определяет функция squre_array ().Это простой старый C-код, поэтому мы должны заключить весь C-код в два набора по три строки в каждом.Эти шесть строк (всего) эффективно сообщают компоновщику, что символы в коде в квадратных скобках являются символами типа C, а не символами типа M ++.Когда компоновщик наконец убедится в этом, он может связать функцию squre_array () с вашей основной программой:
<br> <strong>&#47;&#47; insert magic three lines here, way up at the top of your .c file<br> &#35;ifdef __cplusplus &#47;&#47;if we are compiling as C++, tell<br> extern "C" { &#47;&#47;the compiler that <em>this</em> stuff is plain old C<br> &#35;endif<br><br></strong> &#35;include <stdio.h><br> &#35;include <cuda.h> <strong><-- remember this "glue" file: we'll change it in step 3</strong><br></p> <p><strong>&#47;&#47;_<em>global</em>_ void square_array(float *a, int N) <-- remove the declaration,<br> void square_array(float *a, int N) { <-- but retain the definition</strong> <br> int idx = blockIdx.x * blockDim.x + threadIdx.x;<br> if (idx a[idx] = a[idx] * a[idx];<br> }<br> void squre_array()<br> {<br> float *a_h, *a_d;<br> ... <br> cudaFree(a_d);<br> }<br> <strong>&#47;&#47; close magic three lines<br> &#35;ifdef __cplusplus &#47;&#47;<br> } &#47;&#47; closing curly bracket<br> &#35;endif<br><br></strong> STEP 3:<br>The important thing that is missing from the OP's understanding is that squre_array( ) (and square_array( ), if you want) must be <strong>declared</strong>; 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 &#35;included in the file where main( ) resides (OP: again, why is this?). So let's fix up cuda.h:</p> <p> <strong>&#47;&#47; magic three lines again<br> &#35;ifdef __cplusplus<br> extern "C" {<br> &#35;endif<br></strong> void squre_array();<br> void square_array(float *a, int N);<br> <strong>&#47;&#47; close magic three lines, just like before<br> &#35;ifdef __cplusplus &#47;&#47;<br> } &#47;&#47; closing curly bracket<br> &#35;endif<br><br></strong> И все.Теперь ваша программа будет ссылаться.

- Пит

0 голосов
/ 05 декабря 2012

Предположим, у нас есть функция F, объявленная в файле Fh, определенная в файле Fc, и файл main.cpp, где F #included и вызван.Ваш компилятор C компилирует Fh + Fc в объектный файл Fo;затем компилятор C ++ компилирует Fh + main.cpp в main.o.Однако компиляторы C ++ делают искажение имен , что означает, что функция F, объявленная в Fh, будет переименована компилятором, например, в F_blah.Затем компоновщик попытается объединить main.o и Fo: он найдет вызов F_blah в main.o, но не найдет тело F_blah, потому что компилятор C скомпилировал его как F, а не F_blah.И вот мы с неразрешенной внешней ошибкой символа (LNK2001 в VS).Для подобных случаев вам нужно указать компилятору C ++ оставить имя функции как есть: в вашем .h файле вы объявляете такую ​​функцию внутри следующего блока:

#ifdef  __cplusplus
extern "C" {
#endif

void F();

#ifdef  __cplusplus
}
#endif
...