基于C-exit代码捕获ctypes中的异常

时间:2014-06-22 09:15:33

标签: python c ctypes

我使用C调用Python/numpyctypes编写的共享库。但是,当exit C中使用iPython函数时,C会发生一些意外结果。

考虑以下示例,其中数组“A”的第一项在C中进行了修改。如果值为负,则应引发异常。

#include <stdlib.h> #include <stdio.h> #include <math.h> extern void cfun(double* A) { // raise exception if A[0]<0.0 if ( A[0]<0.0 ) { printf("Negative value of A[0] encountered\n"); exit(1); } // change "A[0]" to it's square A[0] = pow(A[0],2); } - 代码:

gcc -c -fPIC fun.c
gcc -shared -o test.so fun.o

使用

编译
Python

包裹import numpy as np import ctypes # include shared library lib = ctypes.CDLL("./test.so") # link to C-program, including input-typing cfun = lib.cfun cfun.restype = None cfun.argtypes = [ np.ctypeslib.ndpointer(ctypes.c_double,flags="C_CONTIGUOUS") ] # simple example A = np.arange((5),dtype='float')+2. cfun(A) print A # expected output: [ 4. 3. 4. 5. 6.] # simple example A[0] = -10.0 cfun(A) print A # expected output: exception, no output from "print A" - 代码:

[ 4.  3.  4.  5.  6.]
Negative value of A[0] encountered

当我从命令行运行此代码时,程序会执行应有的操作。输出:

iPython

然而,当我从iPython

运行python函数时
  • 想要的行为是引发某种异常,
  • 当前的行为是,遇到错误时,C也存在。

我认为最优雅的解决方案是引入错误流作为(返回)参数来表示成功或失败。但是我真的想避免这种情况。我使用了广泛的{{1}}代码。引入错误流会使所有函数之间的依赖性过度复杂化。

请帮忙!

1 个答案:

答案 0 :(得分:2)

exit调用系统的退出函数并终止正在运行的进程,在你的情况下是ipython。在C中完成错误处理的方法是设置一些全局错误变量并返回状态标志

#include <math.h>

char *error_string;

extern char* get_error_string() {
    return error_string;
}

extern int cfun(double* A)
{
  // raise exception if A[0]<0.0
  if ( A[0]<0.0 ) {
    error_string = "Negative value of A[0] encountered\n";
    return -1;
  }

  // change "A[0]" to it's square
  A[0] = pow(A[0],2);
  return 0;
}

并在Python中测试错误:

import numpy as np
import ctypes

# include shared library
lib = ctypes.CDLL("./test.so")

# link to C-program, including input-typing
get_error          = lib.get_error
get_error.restype  = ctypes.c_char_p
get_error.argtypes = []

def c_error_wrapper(func):
    def method(*args):
        status = func(*args)
        if status<0:
            raise RuntimeError(get_error())
    return method

# link to C-program, including input-typing
cfun          = lib.cfun
cfun.restype  = ctypes.c_int
cfun.argtypes = [ np.ctypeslib.ndpointer(ctypes.c_double,flags="C_CONTIGUOUS") ]

cfun = c_error_wrapper(cfun)

# simple example
A = np.arange((5),dtype='float')+2.
cfun(A)
print A
# expected output: [ 4.  3.  4.  5.  6.]

# simple example
A[0] = -10.0
cfun(A)
print A
# expected output: exception, no output from "print A"