带位字段的Python Ctypes结构与C中的结构具有不同的内存布局

带位字段的Python Ctypes结构与C中的结构具有不同的内存布局,python,c,ctypes,bit-fields,Python,C,Ctypes,Bit Fields,我必须回答有关Ctypes以及它们定义结构的方式的具体问题。为了给你一点上下文,请考虑下面的C中的例子,它定义了一个结构:位字段: #include <stdint.h> #include <stdio.h> struct Version { uint8_t n1; uint8_t n2; uint32_t n3:16; } vv; int main(void) { vv.n1 = 0xab; vv.n2 = 0xef;

我必须回答有关Ctypes以及它们定义结构的方式的具体问题。为了给你一点上下文,请考虑下面的C中的例子,它定义了一个结构:<强>位字段:

#include <stdint.h>
#include <stdio.h>

struct Version
{
    uint8_t  n1;
    uint8_t  n2;
    uint32_t n3:16;
} vv;

int main(void)
{
    vv.n1 = 0xab;
    vv.n2 = 0xef;
    vv.n3 = 0x1234;

    uint8_t* ptr = (uint8_t*)(&vv);
    printf("size %u\n", sizeof(vv));
    for (int i = 0; i < sizeof(vv); ++i) printf("%2x ", ptr[i]);
    printf("\n");
    
    return 0;
}
在这之前一切都很好,但当我使用ctypes在python中编写等效结构时,我得到了一个不同的定义:

from ctypes import *


class Version(Structure):
    _fields_ = [
        ('n1', c_uint8, 8),
        ('n2', c_uint8, 8),
        ('n3', c_uint32, 16),
    ]


vv = Version()
vv.n1 = 0xab
vv.n2 = 0xef
vv.n3 = 0x1234

print('bytes', bytes(vv).hex())
print('size', sizeof(vv))
因为ctypes结构使用5个字节而不是4个字节(这是C选择的)

如果我将python中的
n3
类型从
c_uint32
更改为
c_uint16
,它似乎与用c编写的代码具有相同的布局:

class Version(Structure):
    _fields_ = [
        ('n1', c_uint8, 8),
        ('n2', c_uint8, 8),
        ('n3', c_uint16, 16),
    ]
...

$ python sample.py
bytes abef3412
size 4
如果我将所有内容更改为
c_uint32
,则得到相同的结果:

class Version(Structure):
    _fields_ = [
        ('n1', c_uint32, 8),
        ('n2', c_uint32, 8),
        ('n3', c_uint32, 16),
    ]
...

$ python sample.py
bytes abef3412
size 4
问题
  • 如果Ctypes本机使用c库,为什么会得到不同的结果
  • 为什么在第一个python代码片段中我得到了一个额外的字节?我可以理解它是否是4的倍数,但为什么是5字节
  • 为什么python中最后两个版本的结构定义似乎与C兼容
  • 更新 我打开了一个问题,因为它看起来像一个bug,我将继续用任何更新更新此帖子。

    Hm

    这里()它说

    位字段仅适用于整数字段,位宽度指定为字段元组中的第三项:

    那么,您可能必须对位字段使用type
    c_int

    这里的sizeof可能正在按值传递struct,这是ctypes不支持的

    这里()它说

    位字段仅适用于整数字段,位宽度指定为字段元组中的第三项:

    那么,您可能必须对位字段使用type
    c_int

    这里的sizeof可能正在按值传递struct,这是ctypes不支持的


    您好,谢谢您的回复。doc表示整型字段,而我的POV没有明确地表示c_int,因此任何其他类型仍然可以。现在,如果我使用c_int,它可以工作,并且与我的第三个例子(我使用c_int32)相同,因为c_int32可能是c_int的别名,具体取决于平台类ctypes.c_int32表示c32位有符号int数据类型。通常是c_int的别名。“嗨,谢谢你的回复。doc表示整型字段,而我的POV没有明确地表示c_int,因此任何其他类型仍然可以。现在,如果我使用c_int,它可以工作,并且与我的第三个例子(我使用c_int32)相同,因为c_int32可能是c_int的别名,具体取决于平台类ctypes.c_int32表示c32位有符号int数据类型。通常是c_int的别名。“这个问题似乎与pragmas有关,但没有。我也会继续跟进。这个问题似乎与布拉格有关,但没有布拉格。我也会尝试跟进。
    class Version(Structure):
        _fields_ = [
            ('n1', c_uint32, 8),
            ('n2', c_uint32, 8),
            ('n3', c_uint32, 16),
        ]
    ...
    
    $ python sample.py
    bytes abef3412
    size 4