使用ctypes获取`time_t`的类型/大小

gzjq41n4  于 2023-04-05  发布在  其他
关注(0)|答案(2)|浏览(105)

我正在使用python ctypes模块访问一个包含一些time_t字段的C结构。
由于它的非完全可移植性,我不能静态地将这些字段定义为c_intc_long类型。
如何定义它们以使代码可移植?
示例C结构定义:

#import <sys/types.h>
#import <time.h>

typedef struct my_struct {
    time_t timestap;
    uint16_t code;      
};

相应的python ctypes结构:

from ctypes import *

c_time = ? # What do I have to put here?

class MyStruct(Structure):
    _fields_ = [
        ('timestamp', c_time),
        ('code', c_int16),
    ]
8yoxcaq7

8yoxcaq71#

最好的办法是通过内省脚本运行的系统,并对使用哪种整型进行最佳选择。

if sys.platform == 'win32':
    time_t = ctypes.c_uint64
# ...

底线是time_t没有在标准中定义。这取决于操作系统和编译器。所以你在Python脚本中对time_t的定义取决于你正在与之交互的DLL/。

0g0grzrc

0g0grzrc2#

从Python 3.12开始(撰写本文时仍在开发中,计划于2023年10月发布),ctypes.c_time_t可以用于此,在您的示例中:

# This requires Python 3.12, which adds ctypes.c_time_t

from ctypes import *

class MyStruct(Structure):
    _fields_ = [
        ('timestamp', c_time_t),
        ('code', c_int16),
    ]

我有一个last year的用例,the patch被接受了。
如果你还没有Python 3.12,像这样的东西可以做到这一点,尽管它没有涵盖所有情况(从上面的PR/issue):

import platform
import ctypes

if platform.system() == 'Windows':
    # Assume MSVC(?) - what about mingw/clang?
    time_t = ctypes.c_int64
elif ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_int64):
    # 64-bit platform of any kind - assume 64-bit time_t(?)
    time_t = ctypes.c_int64
else:
    # assume some kind of 32-bit platform(?)
    time_t = ctypes.c_int32

# ... use time_t here ...

这对于Windows(MSVC〉= 2005),macOS(x86_64,aarch 64)和Linux(arm 32,aarch 64,x86,x86_64)应该没问题,但可能需要在某些CPU上调整BSD。
一旦Python 3.12发布并且ctypes.c_time_t是一个东西,你就可以使用它了。
例如,这是gPodder的libgpod_ctypes.py如何尝试使用ctypes.c_time_t,但在旧系统上福尔斯了一些简单的启发式方法:

# ctypes.c_time_t will be available in Python 3.12 onwards
# See also: https://github.com/python/cpython/pull/92870
if hasattr(ctypes, 'c_time_t'):
    time_t = ctypes.c_time_t
else:
    # See also: https://github.com/python/cpython/issues/92869
    if ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_int64):
        time_t = ctypes.c_int64
    else:
        # On 32-bit systems, time_t is historically 32-bit, but due to Y2K38
        # there have been efforts to establish 64-bit time_t on 32-bit Linux:
        # https://linux.slashdot.org/story/20/02/15/0247201/linux-is-ready-for-the-end-of-time
        # https://www.gnu.org/software/libc/manual/html_node/64_002dbit-time-symbol-handling.html
        time_t = ctypes.c_int32

相关问题