繁体   English   中英

python ctypes在Windows上出现意外行为

[英]python ctypes unexpected behavior on windows

import ctypes
print(ctypes.c_int32)

在 linux(和 os x)上,此代码返回 <class 'ctypes.c_int32'> 在 windows 上返回 <class 'ctypes.c_long'>

为什么会发生这种情况以及如何解决这个问题? 我只想像在 Linux 上一样在 Windows 上运行软件。

更新

有自定义类

class ctype:
    ....
    ctype.int32 = _make_ctype_from_ctypes(ctypes.c_int32)
    ....

使用此功能:

def _make_ctype_from_ctypes(ctypes_type):
    ctypes_namespace = dict(ctypes_type.__dict__)

    namespace = {
        "__module__": _Numeric.__module__,
        "_type_": ctypes_namespace["_type_"],
    }

    return type(
        ctypes_type.__name__.replace("c_", ""),
        tuple([_Numeric, *ctypes_type.__bases__]),
        namespace,
    )

错误发生在这里:

class _Numeric:
    _type_: str

    def __init__(self, value):
        if isinstance(value, (bytearray, bytes)):
            value = struct.unpack(self._type_, value)[0]
        if isinstance(value, _Numeric):
            value = value.value
        if "int" in self.__class__.__name__:
            value = int(value)
        super().__init__(value) <-------------

堆栈跟踪

Traceback (most recent call last):
  File "C:\Users\wotori\git\L2py\main.py", line 5, in <module>
    print(clock.ticks)
  File "C:\Users\wotori\git\L2py\game\game\models\world.py", line 40, in ticks
    return ctype.int(int(time.time() - self.start_time) / self.MSEC_IN_TICK)
  File "C:\Users\wotori\git\L2py\common\common\ctype.py", line 19, in __init__
    super().__init__(value)
TypeError: 'float' object cannot be interpreted as an integer

我尝试将异常处理程序添加到问题发生的行,以便我们能够查看错误发生的确切数字,但这对我来说没有任何意义:

try:
    super().__init__(value)
except Exception as e:
    print("error", e, value)

错误输出:

error 'float' object cannot be interpreted as an integer 1639347702.44
error 'float' object cannot be interpreted as an integer 0.0

一点提醒,此代码适用于 linux 和 osx,但不适用于 Windows。

更新#2最小的例子。 此代码在 linux 上运行没有错误,但在 windows 上失败。 两台计算机上都安装了相同的 64 位 python。

if __name__ == '__main__':
    from dataclasses import dataclass, field
    import time


    @dataclass(kw_only=True)
    class Clock:
        start_time: int = field(default=int(time.time()))
        _is_night = False
        TICKS_PER_SECOND = 10
        MSEC_IN_TICK = 1000 / TICKS_PER_SECOND

        @property
        def is_night(self):
            return self.hours < 6

        @property
        def hours(self):
            return (self.get_time() / 60) % 24

        @property
        def ticks(self):
            return ctype.int(int(time.time() - self.start_time) / self.MSEC_IN_TICK)

        def get_time(self):
            return ctype.int32(self.ticks / (self.TICKS_PER_SECOND * 10))


    import struct


    class _Numeric:
        _type_: str

        def __init__(self, value):
            if isinstance(value, (bytearray, bytes)):
                value = struct.unpack(self._type_, value)[0]
            if isinstance(value, _Numeric):
                value = value.value
            if "int" in self.__class__.__name__:
                value = int(value)
            super().__init__(value)


    def _make_ctype_from_ctypes(ctypes_type):
        ctypes_namespace = dict(ctypes_type.__dict__)

        namespace = {
            "__module__": _Numeric.__module__,
            "_type_": ctypes_namespace["_type_"],
        }

        return type(
            ctypes_type.__name__.replace("c_", ""),
            tuple([_Numeric, *ctypes_type.__bases__]),
            namespace,
        )


    import ctypes


    class ctype:  # noqa
        int = _make_ctype_from_ctypes(ctypes.c_int)
        int32 = _make_ctype_from_ctypes(ctypes.c_int32)


    clock = Clock()
    print(clock.ticks)

堆栈跟踪:

Traceback (most recent call last):
  File "C:\Users\wotori\git\L2py\main.py", line 69, in <module>
    print(clock.ticks)
  File "C:\Users\wotori\git\L2py\main.py", line 23, in ticks
    return ctype.int(int(time.time() - self.start_time) / self.MSEC_IN_TICK)
  File "C:\Users\wotori\git\L2py\main.py", line 42, in __init__
    super().__init__(value)
TypeError: 'float' object cannot be interpreted as an integer

应该是:int(0)

没有什么可修复的。 在 Windows ctypes.c_intctypes.c_int32ctypes.c_long的别名,因为 C intint32_tlong在 Windows 上都是相同的整数大小。

ctypes 文档

ctypes。 c_int
表示 C 有符号 int 数据类型。 构造函数接受一个可选的整数初始化器; 没有进行溢出检查。 sizeof(int) == sizeof(long)的平台上,它是c_long的别名。
...
ctypes。 c_int32
表示 C 32 位有符号 int 数据类型。 通常是c_int的别名。

编辑

根据代码更新,在 Windows 上ctype.intctype.int32都将是<class '__main__.long'> _Numeric.__init__()中, self.__class__.__name__将是'long' 换行:

if "int" in self.__class__.__name__:

如下所示,它会起作用,因为所有这些类型都需要value = int(value)行将输入valuefloat更改为int

if self.__class__.__name__ in ('int', 'int32', 'long'):

您也可以考虑将这条线设为else:如果三个 if 涵盖了所有基础。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM