如何在Python ctypes中翻译C中的内存地址类型转换?

0 投票
1 回答
572 浏览
提问于 2025-04-16 15:25

抱歉如果标题不太准确,我不太确定它是否正确描述了情况:

我正在尝试使用Python的ctypes模块与FreeTDS C库进行交互。我有一些代码运行得相当不错,但遇到了一些问题。我不太确定如何将下面dbbind()调用的最后一个参数转换为ctypes。

我正在参考的C语言示例是:

  /* these variable types are defined in the FreeTDS library */
  DBINT customer_id;
  DBCHAR company_name[255];
  DBFLT8 avg_income;

  /* <snip> */


  /* Now bind the returned columns to the variables */
  /* BYTE is defined in the FreeTDS library */
  dbbind(dbconn, 1, INTBIND, 0, (BYTE *)&customer_id);
  dbbind(dbconn, 2, NTBSTRINGBIND, 0, (BYTE *)&company_name);
  dbbind(dbconn, 3, FLT8BIND, 0, (BYTE*)&avg_income);

所以,A) 我该如何在Python中将我的变量定义为库中的变量类型,B) 我该如何将“(BYTE *)&company_name”等等转换为ctypes调用呢?

谢谢!

解决方案:多亏了Zuljin,我能够找到以下内容:

import ctypes as ct

#<snip>

cid = ct.c_int()
cname = ct.create_string_buffer(256)
cavgincome = ct.c_float()
dtlib.dbbind(cdbconn, 1, INTBIND, 0, ct.byref(cid))
dtlib.dbbind(cdbconn, 2, NTBSTRINGBIND, 0, cname)
dtlib.dbbind(cdbconn, 3, REALBIND, 0, ct.byref(cavgincome))

while dtlib.dbnextrow(cdbconn) != NO_MORE_ROWS:
    print '%s | %s | %s' % (cid, cname.value, cavgincome)

1 个回答

3

我觉得你应该先看看这些DBINT、DBCHAR、DBFLT8类型背后到底是什么。很可能它们分别对应的是int(整数)、char(字符)和double(双精度浮点数)。对于这些基本类型,你可以找到对应的ctypes类型,可能是c_int、c_char和c_double。

这样你就可以创建Python实例来保存函数返回的值。如果你想把这些值作为指针参数传递,就需要用到byref()这个函数。大概是这样的:

customer_id = c_int()
dbbind(dbconn, 1, INTBIND, 0, byref(customer_id))

补充一下:对于名字,你需要创建一个空的字符缓冲区。为此,ctypes提供了两个函数:create_string_buffer和create_unicode_buffer。通过这两个函数输出的对象可以直接传递给你的函数。下面是一个在Windows上调用普通和Unicode scanf函数的例子(使用Python 3)。

from ctypes import *
libc = cdll.msvcrt

buf = create_string_buffer(256) 
buf_u = create_unicode_buffer(256)

libc.scanf(b"%s",  buf)
libc.wscanf("%s",  buf_u)

print(buf.value)
print(buf_u.value)

撰写回答