#python #c #ctypes #bit-fields
#python #c #ctypes #битовые поля
Вопрос:
У меня есть конкретные вопросы о 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*)(amp;vv);
printf("size %un", sizeof(vv));
for (int i = 0; i < sizeof(vv); i) printf("%2x ", ptr[i]);
printf("n");
return 0;
}
который, похоже, генерирует одно и то же определение как для 32, так и для 64 архитектур:
$ gcc sample.c -o a -m64 -std=gnu99 -w amp;amp; ./a
size 4
ab ef 34 12
$ gcc sample.c -o a -m32 -std=gnu99 -w amp;amp; ./a
size 4
ab ef 34 12
Пока все в порядке, но когда я пишу эквивалентную структуру на python с использованием ctypes, я получаю другое определение:
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 sample.py
bytes abef341200
size 5
и если я изменю тип n3
в python с 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?
Обновить
Я открыл проблему https://bugs.python.org/issue41932 поскольку похоже, что это ошибка, буду продолжать обновлять этот пост любыми обновлениями.
Комментарии:
1. Похоже, эта проблема связана с github.com/python/cpython/pull/19850 но без прагм. Я также попытаюсь продолжить там.
Ответ №1:
Хм.
Здесь (https://docs.python.org/2.5/lib/ctypes-bit-fields-in-structures-unions.html ) это говорит о том, что
Битовые поля возможны только для целых полей, битовая ширина указывается как третий элемент в кортежах полей:
Так что, возможно, вам нужно использовать type c_int
для битовых полей?
Похоже, что sizeof здесь может передавать struct по значению, которое не поддерживается ctypes .
Комментарии:
1. Привет, спасибо за ответ. В документе указаны целочисленные поля, а в моем POV явно не указано c_int , поэтому любой другой тип по-прежнему в порядке. Теперь, если я использую c_int , это работает, и это будет так же, как в моем третьем случае (где я использовал c_int32 ), поскольку c_int32 может быть псевдонимом для c_int в зависимости от платформы. ` класс ctypes.c_int32 представляет 32-разрядный подписанный тип данных C int. Обычно псевдоним для c_int . `