SWIG - C++ 到 python - 将 ULL 值转换为 0 的枚举
SWIG - C++ to python - enum that has ULL values being converted to 0
我有一个遗留的 C++ 代码库,我正在使用 SWIG 为其生成 python 绑定。
在此代码库中,到处都是枚举,它们具有特定的值,然后用于二进制操作。
使用的典型头文件如下所示:
namespace doom
{
class Bar
{
public:
struct FooIdent
{
enum Ident
{
UnknownFoo = 0,
KnownFoo = 1,
MainFoo = 2,
SecondaryFoo = 3
};
};
enum FooPresence
{
Boo = 0x0,
Foo1 = 0x8000000000ULL,
Foo2 = 0x4000000000ULL,
Foo3 = 0x2000000000ULL,
FooWithA1 = 0x1000000000ULL,
FooWithA2 = 0x0800000000ULL,
FooWithA3 = 0x0400000000ULL,
FooWithA4 = 0x0200000000ULL,
FooWithB1 = 0x0100000000ULL,
FooWithB2 = 0x0080000000,
FooWithB3 = 0x0040000000
};
Bar();
void setVesODee( int ves, doom::Bar::FooPresence pr );
void setVesOGoo( int goo, doom::Bar::FooIdent::Ident ide );
int doSomething();
private:
int m_vdee;
int m_vgoo;
};
} // namespace doom
相应的 .cpp
文件将是:
#include "bar.h"
#include <iostream>
namespace doom
{
Bar::Bar()
{
m_vdee = 0;
m_vgoo = 0;
}
void Bar::setVesODee( int ves, doom::Bar::FooPresence pr ) {
m_vdee = static_cast< doom::Bar::FooPresence >( ves | pr );
}
void Bar::setVesOGoo( int goo, doom::Bar::FooIdent::Ident ide ) {
m_vgoo = static_cast< doom::Bar::FooIdent::Ident >( goo | ide );
}
int Bar::doSomething() {
return m_vgoo + m_vdee;
}
} // namespace doom
int main() {
doom::Bar b = doom::Bar();
b.setVesODee(3, doom::Bar::FooWithB2);
b.setVesOGoo(4, doom::Bar::FooIdent::MainFoo);
int c = b.doSomething();
std::cout << c << std::endl;
return 0;
}
.i
文件看起来像这样:
%feature ("flatnested");
%module bar
%{
#include "bar.h";
%}
%rename("Bar_%s", %$isnested) "";
%include "bar.h"
我使用以下命令构建:
swig -python -c++ -py3 bar.i
g++ -fPIC -c $(pkg-config --cflags --libs python3) bar.cpp bar_wrap.cxx
g++ -shared -o _bar.so bar.o bar_wrap.o
然后我使用以下方法测试代码:
import bar
for i in dir(bar.Bar_FooIdent):
if i[0].isupper():
print(f'{i} = 0x{getattr(bar.Bar_FooIdent, i):X}')
print()
for i in dir(bar.Bar):
if i[0].isupper():
print(f'{i} = 0x{getattr(bar.Bar, i):X}')
这输出:
KnownFoo = 0x1
MainFoo = 0x2
SecondaryFoo = 0x3
UnknownFoo = 0x0
Boo = 0x0
Foo1 = 0x0
Foo2 = 0x0
Foo3 = 0x0
FooWithA1 = 0x0
FooWithA2 = 0x0
FooWithA3 = 0x0
FooWithA4 = 0x0
FooWithB1 = 0x0
FooWithB2 = 0x-80000000
FooWithB3 = 0x40000000
似乎 SWIG 没有正确转换 ULL 文字,我不知道如何告诉 SWIG 将这些解释为更大的类型。
我不太习惯使用 SWIG,但我现在已经能凑合使用了一段时间,并且能够生成我需要的大部分代码。我在网上搜索了文档和问题,但无法完成这项工作。进行此转换的任何指示?
默认情况下,SWIG 将枚举常量视为 int
,即使您重写为:
enum FooPresence : unsigned long long { ... }
这会在 test_wrap.cxx
文件中生成如下代码:
SWIG_Python_SetConstant(d, "Foo1",SWIG_From_int(static_cast< int >(Foo1)));
SWIG_Python_SetConstant(d, "Foo2",SWIG_From_int(static_cast< int >(Foo2)));
我能够通过覆盖 constcode
类型映射来假设 64 位整数来获得正确的结果。
test.i
%module test
%typemap(constcode) int %{SWIG_Python_SetConstant(d, "",PyLong_FromLongLong(static_cast<long long>()));%}
%inline %{
enum FooPresence : unsigned long long
{
Foo1 = 0x8000000000ULL,
Foo2 = 0x4000000000ULL,
Foo3 = 0x2000000000ULL,
FooWithA1 = 0x1000000000ULL,
FooWithA2 = 0x0800000000ULL,
FooWithA3 = 0x0400000000ULL,
FooWithA4 = 0x0200000000ULL,
FooWithB1 = 0x0100000000ULL,
FooWithB2 = 0x0080000000,
FooWithB3 = 0x0040000000
};
%}
您可以在构建时使用 -debug-tmsearch
标志查看 SWIG 类型映射匹配搜索。请注意,它正在搜索 int Foo1
而不是 enum FooPresence
或 long long Foo1
:
C:\test>swig -c++ -python -debug-tmsearch test.i
test.i(8) : Searching for a suitable 'consttab' typemap for: int Foo1
Looking for: int Foo1
Looking for: int
Looking for: SWIGTYPE Foo1
Looking for: SWIGTYPE
None found
test.i(8) : Searching for a suitable 'constcode' typemap for: int Foo1
Looking for: int Foo1
Looking for: int
Using: %typemap(constcode) int
...
演示:
>>> import test
>>> hex(test.Foo1)
'0x8000000000'
>>> hex(test.FooWithA1)
'0x1000000000'
我有一个遗留的 C++ 代码库,我正在使用 SWIG 为其生成 python 绑定。 在此代码库中,到处都是枚举,它们具有特定的值,然后用于二进制操作。
使用的典型头文件如下所示:
namespace doom
{
class Bar
{
public:
struct FooIdent
{
enum Ident
{
UnknownFoo = 0,
KnownFoo = 1,
MainFoo = 2,
SecondaryFoo = 3
};
};
enum FooPresence
{
Boo = 0x0,
Foo1 = 0x8000000000ULL,
Foo2 = 0x4000000000ULL,
Foo3 = 0x2000000000ULL,
FooWithA1 = 0x1000000000ULL,
FooWithA2 = 0x0800000000ULL,
FooWithA3 = 0x0400000000ULL,
FooWithA4 = 0x0200000000ULL,
FooWithB1 = 0x0100000000ULL,
FooWithB2 = 0x0080000000,
FooWithB3 = 0x0040000000
};
Bar();
void setVesODee( int ves, doom::Bar::FooPresence pr );
void setVesOGoo( int goo, doom::Bar::FooIdent::Ident ide );
int doSomething();
private:
int m_vdee;
int m_vgoo;
};
} // namespace doom
相应的 .cpp
文件将是:
#include "bar.h"
#include <iostream>
namespace doom
{
Bar::Bar()
{
m_vdee = 0;
m_vgoo = 0;
}
void Bar::setVesODee( int ves, doom::Bar::FooPresence pr ) {
m_vdee = static_cast< doom::Bar::FooPresence >( ves | pr );
}
void Bar::setVesOGoo( int goo, doom::Bar::FooIdent::Ident ide ) {
m_vgoo = static_cast< doom::Bar::FooIdent::Ident >( goo | ide );
}
int Bar::doSomething() {
return m_vgoo + m_vdee;
}
} // namespace doom
int main() {
doom::Bar b = doom::Bar();
b.setVesODee(3, doom::Bar::FooWithB2);
b.setVesOGoo(4, doom::Bar::FooIdent::MainFoo);
int c = b.doSomething();
std::cout << c << std::endl;
return 0;
}
.i
文件看起来像这样:
%feature ("flatnested");
%module bar
%{
#include "bar.h";
%}
%rename("Bar_%s", %$isnested) "";
%include "bar.h"
我使用以下命令构建:
swig -python -c++ -py3 bar.i
g++ -fPIC -c $(pkg-config --cflags --libs python3) bar.cpp bar_wrap.cxx
g++ -shared -o _bar.so bar.o bar_wrap.o
然后我使用以下方法测试代码:
import bar
for i in dir(bar.Bar_FooIdent):
if i[0].isupper():
print(f'{i} = 0x{getattr(bar.Bar_FooIdent, i):X}')
print()
for i in dir(bar.Bar):
if i[0].isupper():
print(f'{i} = 0x{getattr(bar.Bar, i):X}')
这输出:
KnownFoo = 0x1
MainFoo = 0x2
SecondaryFoo = 0x3
UnknownFoo = 0x0
Boo = 0x0
Foo1 = 0x0
Foo2 = 0x0
Foo3 = 0x0
FooWithA1 = 0x0
FooWithA2 = 0x0
FooWithA3 = 0x0
FooWithA4 = 0x0
FooWithB1 = 0x0
FooWithB2 = 0x-80000000
FooWithB3 = 0x40000000
似乎 SWIG 没有正确转换 ULL 文字,我不知道如何告诉 SWIG 将这些解释为更大的类型。
我不太习惯使用 SWIG,但我现在已经能凑合使用了一段时间,并且能够生成我需要的大部分代码。我在网上搜索了文档和问题,但无法完成这项工作。进行此转换的任何指示?
默认情况下,SWIG 将枚举常量视为 int
,即使您重写为:
enum FooPresence : unsigned long long { ... }
这会在 test_wrap.cxx
文件中生成如下代码:
SWIG_Python_SetConstant(d, "Foo1",SWIG_From_int(static_cast< int >(Foo1)));
SWIG_Python_SetConstant(d, "Foo2",SWIG_From_int(static_cast< int >(Foo2)));
我能够通过覆盖 constcode
类型映射来假设 64 位整数来获得正确的结果。
test.i
%module test
%typemap(constcode) int %{SWIG_Python_SetConstant(d, "",PyLong_FromLongLong(static_cast<long long>()));%}
%inline %{
enum FooPresence : unsigned long long
{
Foo1 = 0x8000000000ULL,
Foo2 = 0x4000000000ULL,
Foo3 = 0x2000000000ULL,
FooWithA1 = 0x1000000000ULL,
FooWithA2 = 0x0800000000ULL,
FooWithA3 = 0x0400000000ULL,
FooWithA4 = 0x0200000000ULL,
FooWithB1 = 0x0100000000ULL,
FooWithB2 = 0x0080000000,
FooWithB3 = 0x0040000000
};
%}
您可以在构建时使用 -debug-tmsearch
标志查看 SWIG 类型映射匹配搜索。请注意,它正在搜索 int Foo1
而不是 enum FooPresence
或 long long Foo1
:
C:\test>swig -c++ -python -debug-tmsearch test.i
test.i(8) : Searching for a suitable 'consttab' typemap for: int Foo1
Looking for: int Foo1
Looking for: int
Looking for: SWIGTYPE Foo1
Looking for: SWIGTYPE
None found
test.i(8) : Searching for a suitable 'constcode' typemap for: int Foo1
Looking for: int Foo1
Looking for: int
Using: %typemap(constcode) int
...
演示:
>>> import test
>>> hex(test.Foo1)
'0x8000000000'
>>> hex(test.FooWithA1)
'0x1000000000'