为啥 printf() 在 python 中给出一个奇怪的输出?
Posted
技术标签:
【中文标题】为啥 printf() 在 python 中给出一个奇怪的输出?【英文标题】:Why is printf() giving a strange output in python?为什么 printf() 在 python 中给出一个奇怪的输出? 【发布时间】:2017-04-29 19:55:12 【问题描述】:我尝试在 Linux 的 python 命令行中使用 C 函数 printf()
。为了完成这项工作,我导入了ctypes
。我的问题是:如果我创建一个 CDLL
的对象以在循环中使用 printf()
函数,我会得到一个非常奇怪的输出:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6")
>>> for i in range(10):
... libc.printf("%d", i)
...
01
11
21
31
41
51
61
71
81
91
>>>
但是,当我在函数内调用此循环时,它按预期工作:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6")
>>> def pr():
... for i in range(10):
... libc.printf("%d", i)
... libc.printf("\n")
...
>>> pr()
0123456789
>>>
我无法猜测是什么导致了这种行为... 如果重要的话,我会在 Linux 上使用 Python 2.7.6。
编辑:
Python 版本/操作系统对此没有影响。有关详细信息,请参阅下面的 PM 2Ring 的答案。在 Windows 上,您只需将 libc
的初始化更改为 libc = ctypes.CDLL("msvcrt.dll")
,其中 .dll
是可选的。除了调用函数之外,获得正确输出的另一种方法是将printf()
的返回值存储在变量中:
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6") # "mscvrt.dll" on windows
>>> for i in range(10):
... r = libc.printf("%d", i)
...
0123456789>>>
我还是更喜欢这个函数,因为你可以更轻松地添加结束换行符。
【问题讨论】:
实际上抑制输出的更简单方法是在末尾添加一个分号:libc.printf("%d", i);
【参考方案1】:
每个数字末尾的那些额外的'1'
s 是来自printf
的返回值,它返回它打印的字符数。交互式解释器中调用的函数的返回值会自动打印出来(除非它是None
)。
事实上,交互式解释器会打印任何未分配的非None
表达式。当然,它会为这些表达式添加一个换行符,这解释了为什么您的第一个代码块中的输出位于不同的行中。
您的pr
函数没有返回语句,因此它返回None
,因此不会打印额外的内容。
【讨论】:
并且它没有在函数中打印出来,因为函数代码不再是交互式的了? @Aemyl 基本上。您在交互式上下文中调用pr
,因此它的返回值由解释器打印,但pr
调用的任何函数都可以正常工作,否则终端将充满不需要的垃圾。 :)
@Aemyl 不,这是标准(CPython)解释器的所有版本和所有操作系统的标准。 还有其他 Python 解释器/IDE,但默认情况下,它们也会在以交互模式 (AFAIK) 运行时打印非None
表达式的值,尽管它们也可能会打印其他信息。
没有 printf 调用也一样:for i in range(10): 1
注意:ipython
(一个非常常见的替代交互式解释器,它包装了 CPython 解释器,作为众多功能之一)更智能,并且不输出结果块中未分配的表达式。它仅输出未分配的单个表达式。【参考方案2】:
虽然 PM 2Ring 已经很好地回答了这个问题,但我认为值得指出 printf 的行为或非常接近的行为可以作为 python 内置使用,所以你使用 C 真的很奇怪库版本,除非您使用它来学习如何使用ctypes
,在这种情况下继续。
但另一方面,当你没有使用足够多的 python 来了解 REPL 的工作原理时,想要使用 ctypes
是很奇怪的...冒着听起来傲慢的风险,作为一个拥有 10 年 python 经验的人,我实际上从未使用过ctypes
。
python中有两个内置的字符串格式化选项:
print("%d" % (i,))
这是旧样式,与printf非常相似,并且
print(":d".format(i))
这是 python 3 的新功能,并且功能更强大。有questions 解决此站点上的差异。上述两行的输出都与libc.printf("%d\n", i)
相同。也可以print without the newline。
“%”字符串格式化的 CPython 实现实际上使用了 sprintf under the hood。
【讨论】:
我同意在 Python 中使用 C 语言的printf
几乎没有任何意义,除了作为使用 ctypes
的学习练习。我想它返回打印的字符数 可能 很方便,但使用普通的 Python 字符串格式并在打印之前获取结果的len
会更明智。 FWIW,format
函数和方法已被向后移植到 Python 2.6 和 2.7。 Python 3 引入了另一种格式化字符串的方法:Literal String Interpolation aka f-strings。
FWIW,我也没有经常使用ctypes
,但here 是我编写的一个程序,它使用它来访问 OpenSSL 加密库以实现可恢复的 SHA256 哈希函数。 以上是关于为啥 printf() 在 python 中给出一个奇怪的输出?的主要内容,如果未能解决你的问题,请参考以下文章
python - 为啥在python中使用int()将二进制转换为整数会在将2作为基本参数时给出错误
第一次提问:为啥'py'被识别但'python'不被识别?在终端中运行的快捷方式? 'echo %PATH%' 给出巨大的路径?