ctypes:从 Python 调用 C 库
加载共享库,并使用 ctypes 调用 C 函数。
ctypes:从 Python 调用 C 库 是 CoddyKit 上的免费 Python Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Python Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Python Academy 课程共包含 4 节课。
什么是 ctypes
ctypes 是标准库模块,可用于加载共享 C 库并从 Python 调用其中的函数,无需编译。
import ctypes
# Load the C standard library
libc = ctypes.CDLL("libc.so.6") # Linux
# libc = ctypes.CDLL("libSystem.dylib") # macOS
libc.puts(b"Hello from C!")加载库
对于 cdecl 调用约定(大多数 C 库),请使用 ctypes.CDLL;对于 Windows stdcall 接口,请使用 WinDLL。
import ctypes
# Platform-independent approach:
import ctypes.util
libm_name = ctypes.util.find_library("m")
libm = ctypes.CDLL(libm_name)
result = libm.sqrt
result.restype = ctypes.c_double
result.argtypes = [ctypes.c_double]
print(result(2.0)) # 1.4142...C 数据类型
请使用 ctypes 类将 Python 类型映射为 C 类型:c_int、c_double、c_char_p、c_void_p 等。
import ctypes
x = ctypes.c_int(42)
print(x.value) # 42
d = ctypes.c_double(3.14)
print(d.value) # 3.14
s = ctypes.c_char_p(b"hello")
print(s.value) # b"hello"设置 argtypes 和 restype
请始终声明 argtypes(参数类型)和 restype(返回类型),以避免类型不匹配导致的静默崩溃。
import ctypes, ctypes.util
libm = ctypes.CDLL(ctypes.util.find_library("m"))
libm.pow.argtypes = [ctypes.c_double, ctypes.c_double]
libm.pow.restype = ctypes.c_double
print(libm.pow(2.0, 10.0)) # 1024.0传递指针
请使用 ctypes.byref(var) 或 ctypes.pointer(var),将指针传递给 C 变量。
import ctypes
libc = ctypes.CDLL(None) # None = current process
value = ctypes.c_int(0)
# Passing pointer to C function:
# libc.some_func(ctypes.byref(value))
print(value.value)结构体
请通过继承 ctypes.Structure 并列出 _fields_ 来定义 C 结构体。
import ctypes
class Point(ctypes.Structure):
_fields_ = [
("x", ctypes.c_double),
("y", ctypes.c_double),
]
p = Point(1.0, 2.0)
print(p.x, p.y) # 1.0 2.0数组
请使用 TypeClass * N 创建 C 数组。
import ctypes
IntArray5 = ctypes.c_int * 5
arr = IntArray5(10, 20, 30, 40, 50)
for v in arr:
print(v, end=" ") # 10 20 30 40 50回调(函数指针)
请使用 ctypes.CFUNCTYPE 创建可由 C 调用的 Python 函数,并将其作为回调传递。
import ctypes
CompareFunc = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int)
def my_compare(a, b):
return a - b
c_compare = CompareFunc(my_compare)
# Pass c_compare to a C function expecting a comparator加载 Windows DLL
在 Windows 上,对于使用 stdcall 调用约定的 DLL(例如 Windows API),请使用 ctypes.WinDLL。
import ctypes # Windows only
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
kernel32.GetTickCount.restype = ctypes.c_ulong
print(kernel32.GetTickCount())错误处理
请检查 ctypes.get_last_error()(Windows),或者对于以特殊值返回的错误,使用 Python 层面的 try/except。
import ctypes
# Many C functions return -1 or NULL on error:
result = some_c_function()
if result == -1:
raise OSError("C function failed")
# For errno on POSIX:
import os
if result < 0:
raise OSError(os.strerror(ctypes.get_errno()))实际示例:使用 OpenSSL 实现 SHA-256
通过 ctypes 直接调用 OpenSSL 的 SHA256,无需任何 Python 绑定库。
import ctypes, ctypes.util
libcrypto = ctypes.CDLL(ctypes.util.find_library("crypto"))
SHA256 = libcrypto.SHA256
SHA256.argtypes = [ctypes.c_char_p, ctypes.c_size_t, ctypes.c_char_p]
SHA256.restype = ctypes.c_char_p
buf = ctypes.create_string_buffer(32)
SHA256(b"hello", 5, buf)
print(buf.raw.hex())快速检查
为什么应该始终为 ctypes 函数设置 argtypes 和 restype?
总结
ctypes 可以在不编译的情况下加载共享 C 库。请为每个函数声明 argtypes 和 restype。请使用 Structure 表示 C 结构体,使用 TypeClass * N 表示数组,并使用 CFUNCTYPE 表示回调。
常见问题解答
「ctypes:从 Python 调用 C 库」课时是免费的吗?
是的 — 「ctypes:从 Python 调用 C 库」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Python Academy 课程的其余内容,请升级到 CoddyKit PRO。 Python Academy 课程共包含 4 节课。
「ctypes:从 Python 调用 C 库」这节课中我会学到什么?
加载共享库,并使用 ctypes 调用 C 函数。 你通过在浏览器中直接运行的动手代码来练习 Python Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Python Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Python Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「ctypes:从 Python 调用 C 库」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Python Academy 课中编写并运行代码吗?
能。每节 Python Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 为何使用 C 扩展?使用场景与权衡
- ctypes:从 Python 调用 C 库
- cffi:C 外部函数接口
- 编写 Python C 扩展模块