双向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 ,这显然是错误的(确切地说是未定义的行为)。 你的实现(合法地)选择为这个未定义的行为做最简单的事情,这大致是从intfloat的逐步转换。 (它可以做任何事情 ,甚至每次运行都有不同的东西 – 这是未定义行为的美妙)。

您可以通过将其更改为以下内容来修复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; 

或使其成为浮点/双。