1

I am having a problem with a C++ program. I want to use a function which is defined in a C file in a C++ file. Here is my code for the C++ file:

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

int main() {
    squre_array();
}

Now here is the code for the C file in which I defined 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);
}

Now can any one tell me how to link this function to my C++ program? Every time I compile the program, I got the error message:

cpp:: undefined reference to `squre_array()'

Can anyone tell me what I was doing wrong? How can I link the squre_array() function into my C++ program?

1
  • What is square_array <<< n_blocks, block_size >>> (a_d, N); ? It doesn't look like C code. Commented Mar 16, 2011 at 6:52

4 Answers 4

6

In the C++ code you need to declare the C function as extern "C"

extern "C" void squre_array();
Sign up to request clarification or add additional context in comments.

1 Comment

ya i did that it still not working if i mention void squre_array ();
3

Before the first line of your code snippet, add the three lines:

#ifdef  __cplusplus
extern "C" {
#endif

After the final line of your code snippet, add the three lines:

#ifdef  __cplusplus
}
#endif

Magic? No, it's only that the C and C++ compilers save your code's symbols in different formats; this lets the C++ linker understand the C symbols in your code snippet.

--pete

3 Comments

thanx for help but cant uderstand exact location to put these line or in which code c code or c++ code .please note thati,m using 2 differnt file
@user513164 Indeed, it's an awful answer. Those before and after segments would be used in header files that declare C functions that you want to use in both C and C++ code, which is a common usage but not the usage in the code you posted. For that you can use Arve's answer.
hi thank you for ur support and answer but can u explain me the process completly how to do this
2

Step-by-step, let's modify the OP's code as it now (Mar 17 at 0600 eastern) appears, after the OP applied a few edits:

STEP 1:
Consider snippet 1, which is the C++ int main( ) prog. The linker will try to do what you want, which is to make squre_array( ) accessible -- i.e., callable -- from main( ). In this C++ file, you must #include the header file that declares squre_array( ) to be a C-language function -- the one and only crucial point in this whole process -- rather than a C++ function. (Why? Because the compiler formats and stores C-language symbols differently from C++ symbols; and so when the linker comes along, the C-type symbol defined in the C source is not the same as the C++-type symbol referenced in main( ).) Now, is that header file named cuda.h? Let's assume it is. Remember that such a declaration makes "extern void squre_array( )" superfluous and confusing, so take that line out of this source file:

#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(); }

STEP 2:
Now consider snippet 2, which defines the squre_array( ) function. This is plain old C code so we have to bracket all of that C code with two sets of three lines each. These six lines (total) effectively tell the linker that the symbols in the bracketed code are C-type symbols rather than C++-type"munged" symbols. When the linker is finally convinced of that, it can link the squre_array( ) function into your main program:

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

And that's it. Now your program will link.

-- pete

Comments

0

Consider we have a function F declared in a F.h file, defined in a F.c file and a main.cpp, where F is #included and called. Your C compiler compiles F.h + F.c into an object file F.o; then the C++ compiler compiles F.h + main.cpp into main.o. However C++ compilers do name mangling, which means that function F declared in F.h would be renamed by compiler into for example F_blah. Then linker would try to combine main.o and F.o: it will find the call to F_blah in main.o, but it will not find the body of F_blah, because the C compiler compiled it as F, not F_blah. And here we are with the unresolved external symbol error (LNK2001 in VS). For the cases like this you need to tell C++ compiler to keep the name of the function as is: in your .h file you declare such function inside of the following block:

#ifdef  __cplusplus
extern "C" {
#endif

void F();

#ifdef  __cplusplus
}
#endif

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.