2

PythonでCを使用するためのSWIGを学んでいます。私はこの関数を作成しましたが、ラップされたものmyfuncが間違ったfloat/double値を返す理由を理解できません。

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);

最後に、33.33333ではなく1107558400.0を取得します。

>>>インポートmfuncs
>>> mfuncs.myfunc(3)
1107558400.0
>>>

間違いはどこにありますか?

4

2 に答える 2

4

SWIG タイプマップは不要です。デフォルトで提供されています。「難解な」タイプのタイプマップのみを記述する必要があり、提供されているデフォルトdouble/floatのもので問題ありません。

ここでの本当の問題は、警告を有効にしたり無視したりしてコンパイルしていないことです! 「-Wall -Wextra」またはコンパイラが最大の警告を有効にしてそれらに注意するために必要とするものを使用してコンパイルする習慣を身につけるのは本当に価値があります。

SWIG インターフェースはSWIGに関数についてのみmyfunc通知しますが、そのインターフェースには、生成された myfuncs_wrap.c をコンパイルするために使用するコンパイラーが宣言を使用できるようにするものは何もありません。これは、共有ライブラリをコンパイルする際に、 の暗黙の宣言に依存していることを意味しますmyfunc。-Wall を使用した私のマシンの GCC は、次のように報告します。

test_wrap.c:3139:3: 警告: 関数 'myfunc' の暗黙的な宣言

暗黙の宣言は、それが を返すことを前提としていますint。宣言がない場合、それはCのルールにすぎません。次のように書いたようです。

#include <stdlib.h>

int myfunc(int n);

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

myfuncreturn aの定義を考えると、これは明らかに間違っています (正確には未定義の動作です) floatintあなたの実装は(合法的に)この未定義の動作に対して最も単純なことを行うことを選択します。これはおおよそ からへのビット単位のキャストfloatです。(実行ごとに異なる何かを実行することもできます - それが未定義の動作の美しさです)

SWIG インターフェイスを次のように変更することで修正できます。

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

extern float myfunc(int n);

これが機能するのは、%{との間のコード%}が生成されたラッパーに直接渡されるためです。これにより、コンパイラーmyfuncはラッパーのビルド時に の実際の宣言を認識します。

ただし、私の見解ではより良い解決策があります。宣言をヘッダーファイルで1回だけ提供すると、インターフェイスファイルは次のようになります。

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

%include "myfunc.h"

(そして明らか#include "myfunc.h"にmyfunc.cにあります)。そうすれば、宣言を 1 回書くだけで、コンパイラーは (通常は間違った) 最良の推測を行うのではなく、予期しないものがあれば警告/エラーを出します。

于 2012-07-09T16:02:51.360 に答える
1

このコードには、myfunc(3)期待する 33.3333 を返すことを妨げる 2 つのバグがあります。Flexo はラッピングの問題を見事に説明してくれました。他の問題はこの行です

    result = 100 / n;

100は int です、nは int です。除算の結果は int になり、THEN は float にキャストされます。== 33. Python 2 は同じように動作します。Python myfunc(3)3 では、2 つの int の除算が float になるように変更されています。

その行を次のように変更するだけです

    result = 100.0 / n;

またはnfloat/double を作成します。

于 2012-07-15T03:17:47.073 に答える