0

I have written a C++ application and within it, I need to call a math function that was written in C. The prototype looks like:

void Jacobi_Cyclic_Method(double *eigenvalues, double *eigenvectors, double *A, int n);

My problem is that I can't seem to pass the function double * (for instance both eigenvectors and A are multi-dimensional arrays. The C++ way to pass those things seems to be

double [][size]

I have read about extern C but I don't think it applies here since I am not interfacing with an object but with source itself. How can I send that C function my multi-dimensional arrays defined as such:

double [100][100] A;
double [100][100] eigenvectors;
double [100] eigenvalues;

Trying to compile I get:

error: no matching function for call to ‘MathEngine::Jacobi_Cyclic_Method(double 
[100], double [100][100], double [100][100], int)’
mathEngine.h:9: note: candidates are: static void    
MathEngine::Jacobi_Cyclic_Method(double*, double*, double*, int)
Andrew G
  • 1,457
  • 1
  • 13
  • 26
  • Are you re-compiling everything, including your math function's implementation, or are you linking to an existing compiled library? That matters a lot as to whether `extern "C"` matters or not – Kevin Anderson Apr 25 '12 at 03:35
  • The same way that you would do it had your arrays been defined in C. – Kiril Apr 25 '12 at 03:36
  • You should just be able to pass these values in directly. A `double[100]` is a `double *`, and so is a `double[100][100]`. What goes wrong when you try? – Dawood ibn Kareem Apr 25 '12 at 03:37
  • 7
    Your C prototype requires one-dimension arrays for eigenvalues, eigenvectors, and A. Am I missing something? – Sergey Kalinichenko Apr 25 '12 at 03:37
  • I am recompiling from it's source. When I try to compile I edited my post with what I get when I try to compile – Andrew G Apr 25 '12 at 03:39
  • Note that MathEngine is just a class I am using to hold a bunch of static methods. – Andrew G Apr 25 '12 at 03:41

2 Answers2

1

Probably the problem is that your Jacobi_Cyclic_Method function requires the matrix to be in either column or row major format, where every column/row is stored consecutively in a single, one-dimensional array. E.g. for a row major matrix of size m x n, the elements in any given row are stored contiguously and the item in row i and column j would be at position i*n+j (for zero-based indices i and j). If the matrix is column-major, it would be at position i+j*m.

Using multi-dimensional arrays in C/C++ is often not what you want because something like

double A[100][100];

is not a two-dimensional array, but a single array of length 100 containing pointers to arrays of length 100. Consequently, the rows in A are not stored contiguously.

Michael Wild
  • 21,851
  • 3
  • 36
  • 40
  • Well, the method is defined here: http://code.google.com/p/biaxmc2/source/browse/trunk/montecarlo2/mc2/src/jacobi_cyclic_method.c?spec=svn98&r=98 It appears that it does indeed accept a double[][]. – Andrew G Apr 26 '12 at 12:12
  • That's what the comments say, but the code says differently. If it accepted `double[][]`, the argument declaration for the matrix should be `double** A`, not `double* A`. -- BTW, what kind of a person are you to chose such a disrespectful, stupid user-name?! – Michael Wild Apr 26 '12 at 13:40
  • Wow! You know I took the name from someone I saw on a game I used to play a while back and certainly wasn't aware of the chemical warfare aspect. I was quite confused at your comment here until I looked it up. I had an avatar of a guy in an orange suit etc, etc. Certainly no offense intended, I apologize. Thank you for pointing that out. – Andrew G Apr 26 '12 at 18:40
  • ;-) Glad you didn't choose that name knowing its meaning. Apologies too, for my harsh reaction. Any ways, I generally prefer it if people choose display names related to their real names. – Michael Wild Apr 26 '12 at 19:02
0

I'm assuming that your C function requires multi-dimensional arrays for some of its parameters and that the prototype is written with pointers to doubles for the array/matrix parameters where the integer parameter indicates the size of each dimension (I guess the matrices are square?). If this is the case then you can pass a pointer to the first element of each array/matrix like this:

Jacobi_Cyclic_Methods(&eigenvalues[0], &eigenvectors[0][0], &A[0][0], 100);

Your initial attempt doesn't work because the type of, for instance, eigenvectors is double[100][100] which decays to double (*)[100], not double *.

This post addresses the issue of pointers and multi-dimensional arrays.

Community
  • 1
  • 1
Sean
  • 4,676
  • 2
  • 22
  • 21
  • 2
    I wouldn't try this unless the function documentation states that a `double[100][100]` is the right format. Check if the function requires row-major or column-major matrix layout. – André Caron Apr 25 '12 at 04:58
  • This makes a lot of sense, I will try it out when I get home. Thanks – Andrew G Apr 26 '12 at 12:13
  • This has the exact effect of casting directly to (double *). Both methods let me compile but I still had issues with how the C function thought the memory was laid out vs how it actually was. That said, this works as a solution to my original post. – Andrew G Apr 27 '12 at 13:58
  • When operating with matrices it's worth remembering that C and C++ store them in row- major order. Iterating over matrices in column-major order can create huge performance problems. Unless the whole matrix fits in a single cache-line you can take a cache-miss every time you increment the column index. – Sean Apr 27 '12 at 16:19