回调函数Python + C DLL上的参数值出错

时间:2013-04-19 14:28:06

标签: python callback ctypes

我有一个导出此功能的C dll:

DECLDIR int runTest (char *historyPath, unsigned int candleNumber, void (*testUpdate)(double percentageOfTestCompleted), void (*testFinished)(void), char **error);  

我正在尝试以这种方式在我的python脚本中使用该函数:

historyFilePath_c = c_char_p(historyFilePath)
candleNumber_c = c_int(1000)
error_c = c_char_p(300);

TEST_UPDATE = CFUNCTYPE(c_int, POINTER(c_double))
testUpdate_c = TEST_UPDATE(testUpdate)

TEST_FINISHED = CFUNCTYPE(c_int)
testFinished_c = TEST_FINISHED(testFinished)

astdll.runTest (historyFilePath_c, candleNumber_c, testUpdate_c, testFinished_c, byref(error_c))

def testUpdate(percentageOfTestCompleted):
  print 'Test running ' , percentageOfTestCompleted[0]
  return True

def testFinished():
  print 'Test finished!!'
  return True

我收到此错误(多次因为回调函数运行了很多次。我只会留下最后一个错误。所有这些都是一样的)

Test running
Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 314, in 'calling callback function'
  File "ast.py", line 67, in testUpdate
    print 'Test running ' , percentageOfTestCompleted[0]
ValueError: NULL pointer access
Test finished!!

1 个答案:

答案 0 :(得分:2)

testUpdate回调按值double取值,而不是指针,两个回调都返回void,即None

candleNumber_c是不必要的,特别是如果您声明argtypes。这同样适用于historyFilePath_c。 Python字符串已经包含指向以null结尾的字符串的指针,这是c_char_p构造函数使用的。

为什么要将error_c初始化为地址300?

以下是一个应该有用的示例:

<强> tmp.py:

from ctypes import *
lib = CDLL('./tmp.so')

c_test_update_t = CFUNCTYPE(None, c_double)
c_test_finished_t = CFUNCTYPE(None)

run_test = lib.runTest
run_test.argtypes = [
    c_char_p, c_uint, c_test_update_t, c_test_finished_t, 
    POINTER(c_char_p)]

def test_update(percent_completed):
    print 'percent completed:', percent_completed
test_update_c = c_test_update_t(test_update)

def test_finished():
    print 'test finished'
test_finished_c = c_test_finished_t(test_finished)

error = c_char_p()
result = run_test(
    'path/to/history', 1000, test_update_c, test_finished_c,
    byref(error))

print result
print error.value

<强> tmp.c:

#include <stdio.h>

char error_string[] = "error string";

int runTest(
      char *historyPath,
      unsigned int candleNumber,
      void (*testUpdate)(double percentageOfTestCompleted),
      void (*testFinished)(void),
      char **error)
{
    printf("historyPath: %s\n", historyPath);
    printf("candleNumber: %d\n", candleNumber);
    testUpdate(0.0);
    testFinished();
    *error = error_string;
    return 0;
}

(只是一个简单的测试库,在Linux上用gcc编译)


<强>输出:

historyPath: path/to/history
candleNumber: 1000
percent completed: 0.0
test finished
0
error string