| 
                            
                                  前段时间接到了一个需求是给一个蓝牙的SDK测试接口的稳定性,将SDK的接口文档给你了,需要每个接口都写一个对应的测试用例,SDK 是用c写的,而我python用的比较熟练些,所有记录下在ctypes库的使用方法。 1 python和c中类型映射ctypes中数据类型 
	
		
			| ctypes 类型 | C 类型 | Python 数据类型 |  
			| c_bool | _Bool | bool (1) |  
			| c_char | char | 单字符字节串对象 |  
			| c_wchar | wchar_t | 单字符字符串 |  
			| c_byte | char | int |  
			| c_ubyte | unsigned char | int |  
			| POINTER(c_ubyte) | uchar* | int |  
			| c_short | short | int |  
			| c_ushort | unsigned short | int |  
			| c_int | int | int |  
			| c_uint | unsigned int | int |  
			| c_long | long | int |  
			| c_ulong | unsigned long | int |  
			| c_longlong | __int64 或 long long | int |  
			| c_ulonglong | unsigned __int64 或 unsigned long long | int |  
			| c_size_t | size_t | int |  
			| c_ssize_t | ssize_t 或 Py_ssize_t | int |  
			| c_float | float | float |  
			| c_double | double | float |  
			| c_longdouble | long double | float |  
			| c_char_p | char * (NUL terminated) | 字节串对象或 None |  
			| c_wchar_p | wchar_t * (NUL terminated) | 字符串或 None |  
			| c_void_p | void * | int 或 None |  2 加载共享库
	
		
			| 1 2 3 4 | import ctypes  # 加载本地的共享库,路径根据实际情况调整  lib = ctypes.CDLL('./libexample.so')  # Linux/macOS平台  # lib = ctypes.WinDLL('example.dll')  # Windows平台 |  3 调用函数
	
		
			| 1 2 3 4 5 6 7 | # 设置参数类型  lib.add.argtypes = [ctypes.c_int, ctypes.c_int]  # 设置返回类型  lib.add.restype = ctypes.c_int  # 调用C函数  result = lib.add(2, 3)  print(result)  # 输出:5 |  4 操作指针在ctypes中,你可以使用pointer和byref来操作指针。 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 | # 创建一个整数数组  arr = (ctypes.c_int * 5)(1, 2, 3, 4, 5)  # 获取指向数组首元素的指针  ptr = ctypes.pointer(arr)  # 通过指针访问数组元素  print(ptr[0])  # 输出:1  # 使用byref创建指向变量的指针  x = ctypes.c_int(10)  px = ctypes.byref(x)  # 通过指针修改变量的值  lib.increment(px)  # 假设有一个increment函数用于增加整数的值  print(x.value)  # 输出:11 |  
	
		
			| 1 2 3 4 5 6 7 8 9 10 | # 调用系统的库函数测试 from ctypes import c_int, c_float, create_string_buffer, CDLL, byref c_lib = CDLL('/lib/x86_64-linux-gnu/libc.so.6') i = c_int() f = c_float() s = create_string_buffer(b"\000" * 32) print(i.value, f.value, repr(s.value)) # brref 传入数据类型返回指针的地址, create_string_buffer返回的是指针 c_lib.sscanf(b"1 3.14 Hello", b"%d %f %s", byref(i), byref(f), s) print(i.value, f.value, repr(s.value)) |  
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from ctypes import c_int, POINTER, cdll i = c_int(42)   # 创建一个int类型变量 pi = POINTER(c_int)(i)  # 定义一个指向int类型的指针 print(pi.contents)   # 打印指针指向的内存地址 print(pi.contents.value)   # 打印指针指向的值 # 定义C库中的函数原型 sum_func = cdll.LoadLibrary('./test1.so').sums sum_func.argtypes = [POINTER(c_int), POINTER(c_int)]    # 定义函数参数类型为指针类型 sum_func.restype = POINTER(c_int)   # 定义函数返回值类型为指针类型 pointer = POINTER(c_int) # 调用sum()函数 a = c_int(1) b = c_int(2) c = sum_func(pointer(a), pointer(b))   # 将a、b的地址传递给sum()函数 print(c.contents.value)   # 打印返回值 |  5 操作结构体和联合体你需要定义结构体或联合体的类型,然后可以创建实例、访问其成员等。 
	
		
			| 1 2 3 4 5 6 7 8 9 | # 定义C语言的结构体类型  class Point(ctypes.Structure):      _fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)]  # 创建结构体的实例  p = Point()  p.x = 10  p.y = 20  # 将结构体的实例传递给C函数  lib.print_point(p)  # 假设有一个print_point函数用于打印点的坐标 |  6 处理字符串字符串通常以字符数组或字符指针的形式存在。在ctypes中,你可以使用create_string_buffer来创建C风格的字符串,或者使用c_char_p来操作字符串指针。 
	
		
			| 1 2 3 4 5 6 7 8 | # 创建C风格的字符串  c_str = ctypes.create_string_buffer(b"Hello, World!")  # 将字符串传递给C函数  lib.print_string(c_str)  # 假设有一个print_string函数用于打印字符串  # 处理C语言中的字符串指针  c_char_p_type = ctypes.POINTER(ctypes.c_char)  c_char_p = c_char_p_type.from_buffer(c_str)  lib.print_string_ptr(c_char_p)  # 假设有一个print_string_ptr函数接收字符串指针 |  7 回调函数c 中很多实现异步的方式通过回调函数事件触发的方式,ctype中也能将ctype定义的函数传入c中执行 
	
		
			| 1 2 3 4 5 6 7 8 9 10 | # include "stdio.h" typedef int (*CallbackFunc)(int, int); int c_sub(int x, int y){     printf("c callback func\n");     return x - y; } void call_callback(CallbackFunc callback){     int result = callback(3, 4);     printf("result from c: %d\n", result); } |  
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 | import ctypes my_lib = ctypes.CDLL("./test2.so") callback_type = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int) def python_sub(a, b):     print("python callback func")     return b - a # 1.调用c中的函数,回调函数从python中传入 python_callback = callback_type(python_sub) my_lib.call_callback(python_callback) # 2.调用c中的函数,回调从c中传入 c_callback = callback_type(my_lib.c_sub) my_lib.call_callback(c_callback) |  
 |