通过ctypes在Python调用C函数传递字节数组与直接C调用结果不一致问题
问题排查与解决
核心差异:数组初始化逻辑不一致
你的C代码与Python代码中,input、state数组的初始化行为完全不同,这是哈希结果不符的直接原因:
C代码的初始化规则
在C语言中:
uint8_t input[38] = {"0"}; uint8_t state[40] = {"0"};
- 仅数组第一个元素被赋值为字符
'0'(对应ASCII码0x30) - 数组剩余未初始化的元素会被自动置为0(C语言局部数组部分初始化的默认规则)
以input数组为例,实际内容是:[0x30, 0x00, 0x00, ..., 0x00](共38个元素,1个0x30,37个0x00)
Python代码的初始化逻辑
而你当前的Python代码:
input = b'00000000000000000000000000000000000000' # 38个'0'字符 state = ctypes.create_string_buffer(b'0000000000000000000000000000000000000000', size=40) # 40个'0'字符
- 数组所有元素均为字符
'0'(ASCII码0x30),没有0值填充的元素
修正后的Python代码
按照C的初始化逻辑调整Python代码,确保数组内容完全对齐:
import ctypes sha = ctypes.CDLL('/path/to/lib/sha_lib.so') func = sha.sha256_inc_finalize # 显式指定参数与返回值类型,避免隐式类型错误 func.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_size_t] func.restype = None # 若函数无返回值,必须显式声明 # 初始化output:第一个元素为'0',其余31个元素为0(与C代码一致) out = ctypes.create_string_buffer(32) out[0] = ord('0') # 初始化state:第一个元素为'0',其余39个元素为0 state = ctypes.create_string_buffer(40) state[0] = ord('0') # 初始化input:第一个元素为'0',其余37个元素为0 input_buf = ctypes.create_string_buffer(38) input_buf[0] = ord('0') func(out, state, input_buf, 38) # 按C的格式输出哈希结果 result = bytes(out).hex() formatted_result = ' '.join([result[i:i+8] for i in range(0, len(result), 8)]) print(formatted_result)
额外注意事项
- 显式声明返回值类型:如果
sha256_inc_finalize是无返回值的void函数,必须设置func.restype = None,否则ctypes会默认将返回值当作int处理,可能破坏栈结构。 - 严谨的类型匹配:若要完全对应C的
uint8_t*,可以替换为ctypes.POINTER(ctypes.c_ubyte),比如:
此时数组可以用func.argtypes = [ctypes.POINTER(ctypes.c_ubyte), ctypes.POINTER(ctypes.c_ubyte), ctypes.POINTER(ctypes.c_ubyte), ctypes.c_size_t](ctypes.c_ubyte * 38)()创建,再设置第一个元素为ord('0')。
内容的提问来源于stack exchange,提问作者MrVanC
相关产品推荐
相关产品推荐

