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

Yury V. Zaytsev yury at shurup.com
Thu Jun 21 12:51:28 EDT 2012


Hi Nathaniel,

On Thu, 2012-06-21 at 16:06 +0100, Nathaniel Smith wrote:
> I suspect that the offending cast here is the one that numpy is doing
> internally via a macro. If you look at __multiarray_api.h, you'll see
> that when you write PyArray_DescrFromScalar and friends you are not
> actually doing a simple function call:

Thanks a lot for your post, your explanation is very concise and
helpful! So it seems that these warnings are technically not in *my*
code, but rather come from macro expansions...

> #define PyArray_DescrFromScalar \
>         (*(PyArray_Descr * (*)(PyObject *)) \
>          PyArray_API[57])
> 
> Here PyArray_API is an array of void* which gets populated when you
> call import_array(). The reason things work this way are too tiresome
> to explain in detail, but it's needed to make dynamic linking play
> well with Python dynamic module loading.

I know that my lack of knowledge about the details of NumPy internals
mostly prevents me from making any suggestions that would make sense (if
only by accident), but I wonder whether it could be possible to replace
the array with individual variables of correct type like PyArray_API_57,
etc. since the final API is anyways created by the code generator...?

> Standard C++ apparently does not guarantee that you can cast a void*
> to a function pointer

Right, the problem kind of doesn't exist in C, because POSIX requires
data and function pointers to be of the same size, otherwise the
platform is just not POSIX-compatible, so you'll get no warnings there.

In C++, however, it's not guaranteed, and so you get the warning, but
AFAIK there is no clean workaround :-/

> I guess the solution would be to come up with some more elaborate cast
> that avoids this warning and works with both C and C++, then teach
> numpy/core/code_generators/* to produce it.

For gcc there is an extension to reinterpret_cast that silences the
warning if activated (see web page that I've mentioned earlier), so I
guess it's a matter making it generate something along the lines of:

#ifdef __cplusplus && __GNUC__ 
    __extension__
    #define PyArray_DescrFromScalar \
            reinterpret_cast<*(PyArray_Descr * (*)(PyObject *))> \
             (PyArray_API[57])
#else
    #define PyArray_DescrFromScalar \
            (*(PyArray_Descr * (*)(PyObject *)) \
             PyArray_API[57])
#endif

Looks like if the above is not acceptable, we are stuck, and it's quite
a bit of a hassle to silence all these warnings in my code. The
union-based solutions only guarantee perfectly undefined behavior :-(

I guess the only option will be then to filter warnings from the build
logs at the CI level...

-- 
Sincerely yours,
Yury V. Zaytsev





More information about the SciPy-User mailing list