【问题标题】:Python 3.5 ctypes libc printf() only prints first byte of string Windows 7/10Python 3.5 ctypes libc printf() 仅打印字符串的第一个字节 Windows 7/10
【发布时间】:2016-05-27 03:06:17
【问题描述】:

我正在尝试遵循 Gray Hat Python 示例之一,它在 Python 2.7 中运行良好,但在 Python 3.5 中,结果被截断。

from ctypes import * 

msvcrt = cdll.msvcrt
message_string = "Hello World!\n"
msvcrt.printf("Testing: %s\n", message_string)

您可以在下面看到上面代码的输出只是字母T

基于与此类似的其他一些帖子,在最后一行添加b 会有所帮助,但随后message_string 会被截断。

from ctypes import * 

msvcrt = cdll.msvcrt
message_string = "Hello World!\n"
msvcrt.printf(b"Testing: %s\n", message_string)

如何在 Windows 7 或 10 上使用 Python 3.5 打印存储在 message_string 变量中的整个字符串?

【问题讨论】:

  • 您是否尝试将文本编码为函数可以处理的字符集?
  • 设置msvcrt.printf.argtypes = (ctypes.c_char_p,) 强制类型检查第一个参数。这个可变参数函数的附加参数取决于格式字符串,所以不要选中它们,但在这里使用常识。 Python 3 使用 Unicode 字符串,因此您必须将字符串编码为 bytes,正如前面的评论所建议的那样。此外,避免使用cdll,因为它全局缓存模块,缓存函数指针,这会导致库和脚本之间的原型冲突(即restypeargtypeserrcheck)。使用msvcrt = ctypes.CDLL('msvcrt')
  • 另外,带一大粒盐的“灰帽蟒”。我已经看过许多基于该书代码的示例,足以知道它充满了随意忽略设置原型的代码,因此许多依赖于指针和模块句柄的代码在 64 位 Windows 中中断,或者正在做适当的错误检查,例如使用WinDLLuse_last_error参数启用ctypes.get_last_errorctypes.set_last_error(基于线程本地存储的安全GetLastErrorSetLastError)。
  • 我确实尝试了 python 站点 16.16. ctypes — A foreign function library for Python 上显示的各种方法,例如 create_string_buffer()create_unicode_buffer(),并且可以使用原生 Python print() 让它们工作。也许最好坚持使用 2.7,尽管我确信我读过一篇文章说不再支持 2.7...

标签: python c windows pydev


【解决方案1】:

让它工作!还需要在变量声明中添加b。这么个小细节……见下面调整后的代码:

from ctypes import * 

msvcrt = CDLL('msvcrt')
message_string = b"Hello World!\n"
msvcrt.printf(b"Testing: %s\n", message_string)

在 Windows 7 64 位、带 Python 3.5 和 Windows 10 64 位、带 Python 3.4 上测试

灰帽 Python - chapter1-printf.py - 示例

【讨论】:

  • b 前缀的小细节,即 bytes 文字,是传递 ASCII 字节字符串 b"Hello World!\n" 与 UTF-16LE 编码字符串(在 Windows 上)@ 之间的区别987654328@.
  • 如果您导入的任何库也定义了类似cdll.msvcrt.printf.argtypes = (c_char_p, c_char_p, c_int) 的内容,那么您的代码又会被破坏,因为printf 将需要3 个参数。 cdllwindll 加载器是个坏主意。将其更改为 msvcrt = CDLL('msvcrt') 以获取对 msvcrt 的私有引用。
  • 感谢@eryksun 的补充见解。我实际上想知道你提到的两点有什么区别。
【解决方案2】:

命令应该是msvcrt.printf("Testing: %s\n" % message_string) - 你有一个逗号代替% 符号

【讨论】:

  • 这个答案是双重错误的。您将 Unicode 字符串传递给printf,这需要bytes(即ctypes.c_char_p),并且通过让Python 进行字符串格式化,您错过了C 的可变参数printf 函数的全部要点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 2015-04-25
  • 2013-08-12
  • 1970-01-01
相关资源
最近更新 更多