14

This is described in many places but i simply cannot get it to work. I am calling a C++ function from Cython:

cimport numpy as np
cdef extern from "test.h" namespace "mytest":
   void test(double *A, int m)

cdef int foo():
  cdef np.ndarray[double,mode="c"] a = np.array([1,2,3,4,5],dtype=float)
  # pass ptr to first element of 'a'
  test(&a[0], len(a))
  return 0

foo()

test.cpp is just:

#include <stdio.h>
namespace mytest {
    void test(double *A, int m)
    {
    for (int i = 0; i < m; i++)
    {
        printf("%d is %f\n", i, A[i]);
    }
    }
}

test.h just has:

namespace mytest {
  void test(double *A, int m);
}

This seems to work but when is np.ascontiguousarray needed? Is it sufficient to do:

cdef np.ndarray[double,mode="c"] a = np.array([1,2,3,4,5],dtype=float)

or do you need:

cdef np.ndarray[double,mode="c"] a = np.ascontiguousarray(np.array([1,2,3,4,5],dtype=float))

second and more importantly, how can this generalize to 2d arrays?

Handling 2d arrays

Here is my attempt at passing 2d numpy arrays to C++ which does not work:

cdef np.ndarray[double,mode="c",ndim=2] a = np.array([[1,2],[3,4]],dtype=float)

which is called as:

test(&a[0,0], a.shape[0], a.shape[1])

in the cpp code:

void test(double *A, int m, int n) 
{ 
  printf("reference 0,0 element\n");
  printf("%f\n", A[0][0]);
}

UPDATE: The correct answer

The correct answer is to use linear indexing for the array and not the [][] syntax. The correct way to print the 2d array is:

for (int i = 0; i < m; i++)
{
    for (int j = 0; j < n; j++)
    {
    printf("%d, %d is %f\n", i, j, A[i*m + j]);
    }
}
7
  • 1
    related: Best Practices for passing numpy data pointer to C Commented Feb 26, 2014 at 23:20
  • @J.F.Sebastian: Thank you I've been reading that thread but it's confusing me more. I am basically trying out the "&arr[0]" method since it makes most sense to me but I haven't seen any examples that work. (I don't want to use ctypes) Commented Feb 26, 2014 at 23:24
  • 1
    In your two dimensional example, it looks to me like you are dereferencing the pointer A twice. For a 2D array you will probably have to do the index arithmetic manually. For example, if you have a C contiguous m x n array and you want to do the C equivalent of NumPy's A[i,j]' you would have to do A[m*i+j]` instead of A[0][0]. Dereferencing the pointer twice will probably crash Python. Commented Feb 26, 2014 at 23:33
  • 1
    m is the number of rows. The datatype is taken care of when you specify the type for the pointer. I'll throw together a quick example. Commented Feb 26, 2014 at 23:59
  • 1
    @user248237dfsf: I've liked the suggestion from the thread to use typed memoryviews (&s[0] syntax to pass to C). Commented Feb 27, 2014 at 0:06

1 Answer 1

6

For 2D arrays, you just need the ndim keyword:

cdef np.ndarray[double, mode="c", ndim=2]

The result may or may not share memory with the original. If it shares memory with the original, then the array may not be contiguous, or may have an unusual striding configuration. In this case, passing the buffer to C/C++ directly will be disastrous.

You should always use ascontiguousarray unless your C/C++ code is prepared to deal with non-contiguous data (in which case you will need to pass in all relevant stride data from Cython into the C function). If the input array is already contiguous, no copy will be made. Make sure to pass a compatible dtype to ascontiguousarray so that you don't risk a second copy (e.g. having to convert from a contiguous float array to a contiguous double array).

Sign up to request clarification or add additional context in comments.

9 Comments

@nneoneo: I had ndim, but had a typo in original post, sorry. adding ndim=2 is necessary to make the array but I still don't know how to access it from C. How can I access it on the C side? Can you show an example?
Seems like it should work if you added ascontiguousarray; what doesn't seem to be working about it?
@nneoneo: try passing the 2d array to a C++ function and printing its elements using A[i][j] - it does not work. Double indexing just gives junk. Do you see what I mean?
Oh, I see the problem. You can't double index like that in C unless you have a double ** (an array of pointers) or a double [][] (a declared 2D array). Otherwise, with just a double *, you have to index manually: A[i*n + j].
In C, you have to use 1D indexing, yes. This is typical when dealing with a buffer of contiguous data. (On multidimensional C arrays, like double [][], the C compiler essentially generates the equivalent 1D indexing operation by multiplying the array dimensions with the indices as appropriate).
|

Your Answer

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