双向PyFloat转换是不正确的
我正在学习SWIG,因为在Python中使用C语言。 我写了这个函数,但我无法理解,为什么包装的myfunc
返回错误的float / double值:
mfuncs.c
#include float myfunc(int n) { float result; result = 100 / n; return result; }
mfuncs.i
%module mfuncs %typemap(out) double, float "$result = PyFloat_FromDouble($1);" extern float myfunc(int n);
最后我得到1107558400.0而不是33.33333。
>>>导入mfuncs >>> mfuncs.myfunc(3) 1107558400.0 >>>
哪里出错了?
SWIG类型映射是不需要的 – 它是默认提供的,您只需要为“深奥”类型编写类型映射,并且这里提供的默认double
/ float
就可以了。
这里真正的问题是你没有启用警告编译或忽略它们! 真的值得养成使用“-Wall -Wextra”编译的习惯,或者编译器需要的任何内容来启用最大警告并注意它们。
你的SWIG接口只告诉SWIG有关函数myfunc
但是该接口中没有任何内容可以使用于编译生成的myfuncs_wrap.c的编译器可以使用该声明。 这意味着当你来编译共享库时,你依赖于myfunc
的隐式声明。 我的机器上的GCC -Wall报告了这个:
test_wrap.c:3139:3:警告:隐式声明函数’myfunc’
隐式声明假定它返回int
。 如果没有声明,这只是C中的规则,就像你写的那样:
#include int myfunc(int n); int main() { printf("%d\n", myfunc(3)); return 0; }
鉴于myfunc
的定义返回一个float
,这显然是错误的(确切地说是未定义的行为)。 你的实现(合法地)选择为这个未定义的行为做最简单的事情,这大致是从int
到float
的逐步转换。 (它可以做任何事情 ,甚至每次运行都有不同的东西 – 这是未定义行为的美妙)。
您可以通过将其更改为以下内容来修复SWIG界面:
%module mfuncs %{ extern float myfunc(int n); %} extern float myfunc(int n);
这是有效的,因为%{
和%}
之间的代码直接传递给生成的包装器,这使得编译器在构建包装器时能够myfunc
的真实声明。
在我的视图中有一个更好的解决方案:在头文件中只提供一次声明,然后您的接口文件变为:
%module mfuncs %{ #include "myfunc.h" %} %include "myfunc.h"
(显然,在myfunc.c中#include "myfunc.h"
)。 通过这种方式,您只需编写一次声明,如果有任何不太令人期待的事情,编译器将发出警告/错误,而不是仅仅采取(通常是错误的)最佳猜测。
您在此代码中有两个错误,阻止myfunc(3)
返回您期望的33.3333。 Flexo奇妙地解释了包装问题。 另一个问题是这一行
result = 100 / n;
100
是int, n
是int,除法的结果是int,而THEN转换为float。 所以myfunc(3)
== 33. Python 2的行为方式相同,它在Python 3中已经改变,因此两个int的划分导致浮点数。
只需将该行更改为
result = 100.0 / n;
或使其成为浮点/双。