Reputation: 1015
I'm defining my structure in python according to the docs (or so I think) but when calling the c function the values don't match:
Python code:
print(f"SchemaID:{appHandResp.supportedAppProtocolRes.SchemaID}, SchemaID_isUsed:{appHandResp.supportedAppProtocolRes.SchemaID_isUsed}")
errn = openv2g.encode_appHandExiDocument(byref(oStream), byref(appHandResp))
C code:
int encode_appHandExiDocument(bitstream_t* stream, struct appHandEXIDocument* exiDoc) {
if (exiDoc->supportedAppProtocolRes_isUsed)
printf("SchemaID:%d, SchemaID_isUsed:%d\n", exiDoc->supportedAppProtocolRes.SchemaID, exiDoc->supportedAppProtocolRes.SchemaID_isUsed);
Output:
# in Python right before calling the C function
SchemaID:2, SchemaID_isUsed:1
# in the C function
SchemaID:1, SchemaID_isUsed:0
The structure definitons:
# Python3.8
appHandresponseCodeType = ctypes.c_uint8
appHandresponseCodeType_OK_SuccessfulNegotiation,\
appHandresponseCodeType_OK_SuccessfulNegotiationWithMinorDeviation,\
appHandresponseCodeType_Failed_NoNegotiation = map(appHandresponseCodeType, range(3))
class appHandAnonType_supportedAppProtocolRes(ctypes.Structure):
_fields_ = [
("ResponseCode", appHandresponseCodeType),
("SchemaID", ctypes.c_uint8),
("SchemaID_isUsed", ctypes.c_uint, 1),
]
.
// C
typedef enum {
appHandresponseCodeType_OK_SuccessfulNegotiation = 0,
appHandresponseCodeType_OK_SuccessfulNegotiationWithMinorDeviation = 1,
appHandresponseCodeType_Failed_NoNegotiation = 2
} appHandresponseCodeType;
struct appHandAnonType_supportedAppProtocolRes {
appHandresponseCodeType ResponseCode ;
uint8_t SchemaID ;
unsigned int SchemaID_isUsed:1;
};
Playing with the structure definition in python I was able to get the expected result:
appHandresponseCodeType = ctypes.c_uint
appHandresponseCodeType_OK_SuccessfulNegotiation,\
appHandresponseCodeType_OK_SuccessfulNegotiationWithMinorDeviation,\
appHandresponseCodeType_Failed_NoNegotiation = map(appHandresponseCodeType, range(3))
class appHandAnonType_supportedAppProtocolRes(ctypes.Structure):
_fields_ = [
("ResponseCode", appHandresponseCodeType),
("SchemaID", ctypes.c_uint8),
("SchemaID_isUsed", ctypes.c_uint8),
]
Output:
# in Python right before calling the C function
SchemaID:2, SchemaID_isUsed:1
# in the C function
SchemaID:2, SchemaID_isUsed:1
I can't explain why this is the case, am I defining my structure in ctypes wrong?
Upvotes: 0
Views: 112
Reputation: 177471
This should work for you. A C enum
is equivalent to a c_int
. You don't need to cast the enum values. Just assign them to ResponseCode
as needed. It is odd to use a bitfield for a single bit. That one bit will still occupy a full c_uint
(typically 32-bits) anyway. There will also normally be three padding bytes between the c_uint8
and the next c_uint
for alignment purposes, unless you also set _pack_
as well (must be before _fields_
if used). Check the C header for any packing directives.
from ctypes import *
appHandresponseCodeType_OK_SuccessfulNegotiation = 0
appHandresponseCodeType_OK_SuccessfulNegotiationWithMinorDeviation = 1
appHandresponseCodeType_Failed_NoNegotiation = 2
class appHandAnonType_supportedAppProtocolRes(Structure):
# _pack_ = 1 # if needed, uncomment.
_fields_ = (('ResponseCode',c_int),
('SchemaID',c_uint8),
('SchemaID_isUsed',c_uint,1))
Upvotes: 1
Reputation: 10435
Not 100%, but I think that this shows the underlying problem:
#include <stdio.h>
typedef struct A {
char x;
unsigned y:1;
} A;
int main() {
printf("%zu\n", sizeof(A));
return 0;
}
prints the value '4' using clang/macos/64bit, gcc/linux/64bit. It is because of the bitfield permitting the compiler to compact the structure.
Upvotes: 1