⚠️ 结构体:一个传值,一个传地址
🔴 这一节的 Python 题会**在运行时调 gcc 现编一个 .so,再用 ctypes 加载进来**——真的跨语言调用,不是假装。判题机需要 gcc、一个可写的临时目录,以及允许 Python 起子进程。⚠️ 这条路线**一个答案都不是耗时**。耗时跟机器、跟负载、跟编译器都有关,换台机器数字就变了。**能当答案的只有"走了多少步"和"两边结果一不一样"。**
import ctypes, os, subprocess, tempfile
def build_c(src, name="m"):
"""把一段 C 现场编成 .so,交回加载好的库。
判题机需要 gcc 和一个可写的临时目录。"""
d = tempfile.mkdtemp()
c_path = os.path.join(d, name + ".c")
so_path = os.path.join(d, name + ".so")
with open(c_path, "w") as f:
f.write(src)
subprocess.run(["gcc", "-shared", "-fPIC", "-O2", "-o", so_path, c_path],
check=True, capture_output=True)
return ctypes.CDLL(so_path)
C_SRC = r"""
typedef struct { int x; int y; } Point;
int area(Point p) { return p.x * p.y; }
void grow(Point *p, int k) { p->x *= k; p->y *= k; }
"""
class Point(ctypes.Structure):
# 字段的**顺序和类型**必须和 C 那边一模一样
_fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)]
lib = build_c(C_SRC)
lib.area.argtypes = [Point]
lib.area.restype = ctypes.c_int
lib.grow.argtypes = [ctypes.POINTER(Point), ctypes.c_int]
lib.grow.restype = None
p = Point(3, 4)
a = lib.area(p) # 传值:C 那边改不到外面
lib.grow(ctypes.byref(p), 2) # 传地址:改得到
print(f"{a}/{p.x}/{p.y}")
全部评论