简体   繁体   中英

Swift missing property from C Flexible Array Member in Struct?

I'm running in to the exact same problem as explained here . Unfortunately, I don't understand what exactly was changed to fix the situation. Did the OP hint to Swift the size of flexible array member to make it visible in Swift? Did the OP modify the C library? I'd like to avoid doing that.

I'm using a C library in Swift that returns a struct with a flexible array member "mbody" at the end.

typedef struct {
    size_t size;
    char mbody[];
} msg

In Swift, when this struct is returned, I have access to the property "size", but not the property "mbody". I've confirmed the mbody is being set properly. A simplified version of the code that initializes the C struct is here:

    const size_t mem_size = msgcount * MSGBOX_SIZE;
    msg* ret = malloc(sizeof(msg) + mem_size);

    if (!ret)
        return NULL;

    ret->size = mem_size;
    memcpy(ret->mbody, msgrecord, MSGBOX_SIZE);

Why is Swift not picking up the size of msg->mbody? Is it a compiler setting? I set it to C99.

I haven't found the proper way to fix this yet, but in case it is never answered, I did find a workaround. I can access the pointer for ret and read the full memory by using ret->size, then advancing off the size of mem_size. I realize there is probably a correct solution out there, and this one still probably has an extra unnecessary step (advance) but I couldn't figure it out yet.

let size = retPointer.pointee.size
let msgRaw = Data(bytes: retPointer, count: (MemoryLayout<msg>.stride + size))
let msgBody = msgRaw.advanced(by: MemoryLayout<Int>.stride) 

In reverse, my workaround is not pretty but works. I'd still appreciate anyone who can show the proper way to handle C flexible array members in structs in Swift. In my workaround, I calculate how many msg objects would need to create a buffer long enough for the body, then copy in to that space.

let totalmem = (mem_size + MemoryLayout<Int>.stride) / MemoryLayout<msg>.stride
let max = Int(ceil(Double(totalmem)) + 1.0)
withUnsafeMutablePointer(to: &msgObj) { orderPtr in
    orderPtr.withMemoryRebound(to: msg.self, capacity: max){ reboundPtr in
        let bodyPtr = UnsafeMutableRawPointer(reboundPtr).advanced(by: MemoryLayout<Int>.stride)
        let bodyBufferPtr = UnsafeMutableRawBufferPointer(start: bodyPtr, count: mem_size)
        body.copyBytes(to: bodyBufferPtr)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM