2

我正在学习 SWIG,用于在 Python 中使用 C。我写了这个函数,但我不明白,为什么包装myfunc返回错误的浮点/双精度值:

mfuncs.c

#include <stdlib.h>

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。

>>> 导入 mfunc
>>> mfuncs.myfunc(3)
1107558400.0
>>>

错误在哪里?

4

2 回答 2

4

不需要 SWIG 类型映射 - 它是默认提供的,您只需要为“深奥”类型编写类型映射,这里提供的默认double/类型float就可以了。

这里真正的问题是您没有在编译时启用或忽略警告!真正值得养成使用“-Wall -Wextra”或您的编译器启用最大警告并注意它们所需的任何东西的习惯。

您的 SWIG 接口仅告诉SWIG该函数myfunc,但该接口中没有任何内容可以使您用于编译生成的 myfuncs_wrap.c 的编译器可以使用该声明。这意味着当您编译共享库时,您依赖于myfunc. 我的机器上的 GCC 和 -Wall 报告了这个:

test_wrap.c:3139:3:警告:函数“myfunc”的隐式声明

隐式声明假定它返回int。如果没有声明,这只是 C 中的规则,就好像你写了:

#include <stdlib.h>

int myfunc(int n);

int main() {
  printf("%d\n", myfunc(3));   
  return 0;
}

myfunc鉴于return a的定义,这显然是错误的(确切地说是未定义的行为)float。您的实现(合法地)选择为这种未定义的行为做最简单的事情,这大致是从intto的按位转换float。(它同样可以做任何事情,甚至在每次运行时都做一些不同的事情——这就是未定义行为的美妙之处)。

您可以通过将其更改为来修复您的 SWIG 界面:

%module mfuncs
%{
extern float myfunc(int n);
%}

extern float myfunc(int n);

这是有效的,因为 和 之间的代码%{直接%}传递给生成的包装器,这使得编译器myfunc在构建包装器时知道真正的声明。

不过,在我看来,有一个更好的解决方案:仅在头文件中提供一次声明,然后您的接口文件变为:

%module mfuncs
%{
#include "myfunc.h"
%}

%include "myfunc.h"

(显然#include "myfunc.h"在 myfunc.c 中)。这样,您只需编写一次声明,如果有任何不完全预期的内容,编译器将发出警告/错误,而不仅仅是采取(通常是错误的)最佳猜测。

于 2012-07-09T16:02:51.360 回答
1

您在此代码中有两个错误会阻止myfunc(3)返回您期望的 33.3333。Flexo 精彩地解释了包装问题。另一个问题是这条线

    result = 100 / n;

100是一个 int,n是一个 int,除法的结果将是一个 int,然后转换为浮点数。所以myfunc(3)== 33。Python 2 的行为方式相同,它在 Python 3 中已进行了更改,使得两个整数的除法产生一个浮点数。

只需将该行更改为

    result = 100.0 / n;

或做n一个浮动/双。

于 2012-07-15T03:17:47.073 回答