我在C中有以下内容
#include <stdio.h>
struct Demo {
char f1:8;
int f2:21;
char f3:2;
char f4:1;
};
int main()
{
struct Demo d = {1, 15, 3, 1};
printf("%ld\n", sizeof(d));
printf("f1=%d|f2=%d|f3=%d|f4=%d", d.f1, d.f2, d.f3, d.f4);
return 0;
}
打印
4
f1=1|f2=15|f3=-1|f4=-1
我一直在用
ctypes.Structure
的位域,并实现了上面的结构。
我的问题是,无论我做什么,我都无法为我的字段设置值。
我在 Python 3.8.10 和 3.9.9 中有以下内容:
from ctypes import Structure, c_byte, c_int, sizeof
class Demo(Structure):
_fields_ = [
('f1', c_byte, 8),
('f2', c_int, 21),
('f3', c_byte, 2),
('f4', c_byte, 1)
]
print(sizeof(Demo))
d = Demo.from_buffer_copy(b'\x01\x0f\x00\xe0')
print(f'{d.f1=}|{d.f2=}|{d.f3=}|{d.f4=}')
打印
1
4
d.f1=1|d.f2=15|d.f3=0|d.f4=0
因此 C 和 Python 定义是等效的,但它们设置的值不是。
字节对象 (
b'\x01\x0f\x00\xe0'
) 是 C 结构的二进制表示,具有以下值(如上所示):
f1
:1f2
:15f3
:-1(3,溢出使它成为-1)f4
:-1(1,溢出使它成为-1)手动设置,或者
from_buffer_copy
,一事无成; f3
和 f4
保持 0.
有人可以帮助我了解如何设置
f3
和f4
,并以相应字段大小的位形式访问它们的值。
通过搜索 https://bugs.python.org,以及过去的 GitHub 问题,我终于遇到了 #59324(11 岁)和 #97588,它们涵盖了与我相同的问题,没有追索权。
虽然似乎有一个待定的 PR 可能会在即将发布的 Python 版本中解决这个问题。
问题是没有在整个 32 位字段中使用相同的类型。当类型发生变化时,将开始一个新的包装并在类型大小的边界上对齐。请参阅下面的注释以及原始和正确结构的大小(以字节为单位)。请注意,
bytes()
可用于 Structure
实例以查看构造后的结果字节。
import ctypes as ct
class Demo1(ct.Structure):
_fields_ = (('f1', ct.c_byte, 8), # 1 byte started
('f2', ct.c_int, 21), # 1 int started (3 bytes padding, then 4 bytes)
('f3', ct.c_byte, 2), # 1 byte started
('f4', ct.c_byte, 1)) # included in previous byte
# 3 bytes structure padding so 'f2' will be aligned in an array of Demo1
def __repr__(self):
return f'Demo1(f1={self.f1}, f2={self.f2}, f3={self.f3}, f4={self.f4})'
class Demo2(ct.Structure):
_fields_ = (('f1', ct.c_int32, 8), # one int started
('f2', ct.c_int32, 21), # included in previous int
('f3', ct.c_int32, 2), # included in previous int
('f4', ct.c_int32, 1)) # included in previous int
def __repr__(self):
return f'Demo2(f1={self.f1}, f2={self.f2}, f3={self.f3}, f4={self.f4})'
print(f'{ct.sizeof(Demo1)=}')
print(f'{ct.sizeof(Demo2)=}')
d1 = Demo1(1, 15, -1, -1) # Set the fields in the constructor
print(d1, bytes(d1)) # Resulting structure and bytes.
d2 = Demo2.from_buffer_copy(b'\x01\x0f\x00\xe0')
print(d2, bytes(d2))
d2 = Demo2(1, 15, -1, -1)
print(d2, bytes(d2))
输出:
ct.sizeof(Demo1)=12
ct.sizeof(Demo2)=4
Demo1(f1=1, f2=15, f3=-1, f4=-1) b'\x01\x00\x00\x00\x0f\x00\x00\x00\x07\x00\x00\x00'
Demo2(f1=1, f2=15, f3=-1, f4=-1) b'\x01\x0f\x00\xe0'
Demo2(f1=1, f2=15, f3=-1, f4=-1) b'\x01\x0f\x00\xe0'