Python与ctypes:为什么printf("%f", 10.1)是错误的
我有一个关于Python中ctypes的疑问。
from ctypes import *
printf = cdll.msvcrt.printf
printf("%s\n", "Hello World!")
printf("%d\n", 100)
printf("%f\n", 10.1)
结果:
Hello World!
100
Traceback (most recent call last):
File "C:\Users\Windows7\Desktop\test.py", line 5, in <module>
printf("%f\n", 10.1)
ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: Don't know how to convert parameter 2
我知道怎么纠正这个错误:10.1应该用c_double(10.1)
来替换,但我想知道为什么在这里要使用c_double()
这个函数?前面两个printf
根本不需要c_string()
或c_int()
。
而且,格式符是"%f",不是"%lf",所以我觉得如果我必须在这里使用ctypes的函数,我应该用c_float()而不是c_double。但是当我尝试printf("%f", c_float(10.1))
时,结果却是错误的:0.000000,为什么会这样?
2 个回答
根据ctypes的文档:
在这些函数调用中,只有None、整数、长整型、字节字符串和Unicode字符串可以直接作为参数使用。None会被当作C语言中的NULL指针传递,字节字符串和Unicode字符串会作为指向它们数据所在内存块的指针传递(char *或wchar_t *)。Python的整数和长整型会被当作平台默认的C语言int类型传递,它们的值会被调整以适应C语言的类型。
所以,你不需要使用c_int或c_string,因为这些都是“原生”的Python对象。
对于你的第二个问题,维基百科上说:
f, F:以正常(定点)表示法表示的双精度浮点数。'f'和'F'的区别在于它们如何打印无限大或NaN(不是一个数字)的字符串('f'打印为'inf'、'infinity',而'F'打印为'INF'、'INFINITY'和'NAN')。
MSDN也说,"f"修饰符是用于双精度类型的。
所以,看起来python-ctypes也参考了相同的文档,并认为使用%f时需要提供一个双精度浮点数。
试试这个:printf("%f", c_double(10.1))
解释一下:printf()
是一个可以接受可变参数的函数。格式参数告诉你在堆栈上可以期待什么类型的数据。
问题是:在查看格式时,无法区分 float
和 double
这两种参数,但 float
占用 4 个字节,而 double
占用 8 个字节。那么 printf()
怎么知道代码中推送到堆栈上的到底是哪种呢?
答案是:float
类型的数据总是会被转换成 double
。这样一来,所有浮点类型在堆栈上使用的字节数都是一样的,printf()
就能搞清楚它们的地址了。