CFUNCTYPE 导致段错误
CFUNCTYPE causes segmentation fault
我有一个简单的 C 代码,它需要一些数字和 returns 一个字符串。
const char * get_err_string(const uint8_t errcode) {
switch (errcode) {
case 0:
return "No errors";
break;
case 1:
return "Some error";
break;
default:
return "There is no such error code";
break;
}
}
我正在尝试使用函数原型 ctypes
来执行它,但我每次都遇到分段错误。
import ctypes
libc = ctypes.cdll.LoadLibrary("lib.so")
get_err_string = ctypes.CFUNCTYPE(
ctypes.c_char_p, # restype
ctypes.c_uint8 # 1st argument
)(libc.get_err_string)
get_err_string(ctypes.c_uint8(0)) # segmentation fault
让我感到惊讶的是,稍微不同的代码执行起来就可以了。
import ctypes
libc = ctypes.cdll.LoadLibrary("genevo/c/bin/genevo.so")
get_err_string = libc.get_err_string
get_err_string.restype = ctypes.c_char_p
get_err_string.argtypes = [ctypes.c_uint8]
get_err_string(ctypes.c_uint8(0)) # b'No errors.'
那么,这是为什么呢?有什么我想念的吗?
CFUNCTYPE
未使用正确的参数调用。请参阅 Function Prototypes in the ctypes 文档(摘录):
Function prototypes created by these factory functions can be
instantiated in different ways, depending on the type and number of
the parameters in the call:
prototype(address)
Returns a foreign function at the specified address
which must be an integer.
prototype(callable)
Create a C callable function (a callback function)
from a Python callable.
prototype(func_spec[, paramflags])
Returns a foreign function exported
by a shared library. func_spec must be a 2-tuple (name_or_ordinal,
library). The first item is the name of the exported function as
string, or the ordinal of the exported function as small integer. The
second item is the shared library instance.
在这种情况下使用上面的第三个版本:
import ctypes as ct
libc = ct.CDLL('./test')
prototype = ct.CFUNCTYPE(ct.c_char_p, ct.c_uint8)
get_err_string = prototype(('get_err_string',libc))
print(get_err_string(0))
// Complete test.c for reference (Windows DLL)
#include <stdint.h>
__declspec(dllexport)
const char * get_err_string(const uint8_t errcode) {
switch (errcode) {
case 0:
return "No errors";
break;
case 1:
return "Some error";
break;
default:
return "There is no such error code";
}
}
输出:
b'No errors'
请注意,第二种方式是 通常 调用函数的方式:
import ctypes as ct
libc = ct.CDLL('./test')
libc.get_err_string.argtypes = ct.c_uint8,
libc.get_err_string.restype = ct.c_char_p
print(libc.get_err_string(0))
输出:
b'No errors'
但是第一种方式有一些优点,即指定哪些参数是 input/output,并分配参数名称和默认值以使其更“Pythonic”。
我有一个简单的 C 代码,它需要一些数字和 returns 一个字符串。
const char * get_err_string(const uint8_t errcode) {
switch (errcode) {
case 0:
return "No errors";
break;
case 1:
return "Some error";
break;
default:
return "There is no such error code";
break;
}
}
我正在尝试使用函数原型 ctypes
来执行它,但我每次都遇到分段错误。
import ctypes
libc = ctypes.cdll.LoadLibrary("lib.so")
get_err_string = ctypes.CFUNCTYPE(
ctypes.c_char_p, # restype
ctypes.c_uint8 # 1st argument
)(libc.get_err_string)
get_err_string(ctypes.c_uint8(0)) # segmentation fault
让我感到惊讶的是,稍微不同的代码执行起来就可以了。
import ctypes
libc = ctypes.cdll.LoadLibrary("genevo/c/bin/genevo.so")
get_err_string = libc.get_err_string
get_err_string.restype = ctypes.c_char_p
get_err_string.argtypes = [ctypes.c_uint8]
get_err_string(ctypes.c_uint8(0)) # b'No errors.'
那么,这是为什么呢?有什么我想念的吗?
CFUNCTYPE
未使用正确的参数调用。请参阅 Function Prototypes in the ctypes 文档(摘录):
Function prototypes created by these factory functions can be instantiated in different ways, depending on the type and number of the parameters in the call:
prototype(address)
Returns a foreign function at the specified address which must be an integer.prototype(callable)
Create a C callable function (a callback function) from a Python callable.prototype(func_spec[, paramflags])
Returns a foreign function exported by a shared library. func_spec must be a 2-tuple (name_or_ordinal, library). The first item is the name of the exported function as string, or the ordinal of the exported function as small integer. The second item is the shared library instance.
在这种情况下使用上面的第三个版本:
import ctypes as ct
libc = ct.CDLL('./test')
prototype = ct.CFUNCTYPE(ct.c_char_p, ct.c_uint8)
get_err_string = prototype(('get_err_string',libc))
print(get_err_string(0))
// Complete test.c for reference (Windows DLL)
#include <stdint.h>
__declspec(dllexport)
const char * get_err_string(const uint8_t errcode) {
switch (errcode) {
case 0:
return "No errors";
break;
case 1:
return "Some error";
break;
default:
return "There is no such error code";
}
}
输出:
b'No errors'
请注意,第二种方式是 通常 调用函数的方式:
import ctypes as ct
libc = ct.CDLL('./test')
libc.get_err_string.argtypes = ct.c_uint8,
libc.get_err_string.restype = ct.c_char_p
print(libc.get_err_string(0))
输出:
b'No errors'
但是第一种方式有一些优点,即指定哪些参数是 input/output,并分配参数名称和默认值以使其更“Pythonic”。