3

I am creating a module for Python with Numpy using the C API and encounter weird incompatibilities with the output of PyArray_SimpleNew, which I would like to understand. But first a minimal example:

# include <Python.h>
# include <numpy/arrayobject.h>

void foo()
{
    Py_Initialize();
    import_array();

    npy_intp dims[1] = {42};
    PyObject * A = PyArray_SimpleNew(1,dims,NPY_DOUBLE); // Line A

    Py_Finalize();
}

int main()
{
    foo();
    return 0;
}

If I compile this with gcc source.c -lpython2.7 -I/usr/include/python2.7 --pedantic, I get (with a reference to Line A):

ISO C forbids conversion of object pointer to function pointer type

So, apparently, PyArrayObjects are expected to be function pointers for some reason.


According to the documentation (e.g., here), PyArray_SimpleNew has a return of type PyObject * and thus the above should be perfectly fine. Moreover, I do not get similar warnings with other functions returning PyObject *.

Now, while this is only a warning we are talking about and my programs using PyArray_SimpleNew work as intended, all this indicates that the Numpy C API is not working as I think it is (or has a bug). Therefore I would like to understand the reason behind this.


I produced the above on the following systems:

  • GCC 4.7.2 (Debian 4.7.2-5), Numpy 1.6.2
  • GCC 4.8.2 (Ubuntu 4.8.2-19ubuntu1), Numpy 1.8.2

In neither case, the situation changes with # define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION.

4
  • I can't reproduce this. How does your gcc command succeed (with just a warning), when you haven't told it where to find the numpy header files? I would expect an argument of the form -I /path/to/installed/numpy/core/include as part of that gcc comand. (Also, what platform and OS are you using? Which version of gcc? Which version of numpy?) Commented Mar 10, 2015 at 13:42
  • @WarrenWeckesser: I think -I/usr/include/python2.7 suffices on my systems (see edit) and I am pretty sure that this is unrelated to the problem. Numpy’s get_include should give you the relevant flags for your system. I added the specifications for which I could produce the warning. Commented Mar 10, 2015 at 14:26
  • What does numpy's get_include() return on your system(s)? Commented Mar 10, 2015 at 18:52
  • Nevermind. I see that in Ubuntu, there is a symlink in /usr/include/python2.7 to numpy's include directory. Commented Mar 10, 2015 at 20:36

1 Answer 1

4

To answer your question about why you're receiving a warning about "ISO C forbids conversion of object pointer to function pointer type", I examined the source code for numpy.

PyArray_SimpleNew is a macro defined in numpy/ndarrayobject.h on line 125:

#define PyArray_SimpleNew(nd, dims, typenum) \
        PyArray_New(&PyArray_Type, nd, dims, typenum, NULL, NULL, 0, 0, NULL)

Which will expand line A as:

PyObject * A = PyArray_New(&PyArray_Type, 1, dims, typenum, NULL, NULL, 0, 0, NULL); // Line A

PyArray_New is itself a macro defined in numpy/__multiarray_api.h on line 1017:

#define PyArray_New \
        (*(PyObject * (*)(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *)) \
         PyArray_API[93])

Which will expand line A as:

PyObject * A = (*(PyObject * (*)(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *))
                PyArray_API[93])(&PyArray_Type, 1, dims, typenum, NULL, NULL, 0, 0, NULL); // Line A

This complex expression can be simplified to:

// PyObject * function93(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *)
typedef PyObject * (*function93)(PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *);

// Get the PyArray API function #93, cast the function pointer to its
// signature, and call it with the arguments to `PyArray_New`.
PyObject * A = (*(function93) PyArray_API[93])(&PyArray_Type, 1, dims, typenum, NULL, NULL, 0, 0, NULL); // Line A

The part causing the forbidden conversion is:

*(function93) PyArray_API[93]

In numpy/__multiarray_api.h on lines 807, 810, and 812 PyArray_API is declared as void **. So PyArray_API[93] is a void * (i.e., an object pointer) which is being cast as a function pointer.

I'm not really familiar with NumPy or its C-api, but it looks like you are using it properly. NumPy just happens to be using some non-standard, undefined behavior internally that GCC supports but the ISO standard does not (i.e., NumPy is not portable by the ISO standard).

See also [SciPy-User] NumPy C API: where does casting pointer-to-object to pointer-to-function come from?

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

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.