0

I need to write a struct to a filedescriptor. I have code in C that works, however when I try to create a struct of the same layout in memory, the result is different. In C, the struct is initialized using designated initializers. In C++, in the header file I am defining the structure and initialize every member in an init function in the implementation. Below are both code snippets. Thank you!

struct in C:

 static const struct {
        struct usb_functionfs_descs_head header;
        struct {
            struct usb_interface_descriptor intf;
            struct usb_endpoint_descriptor_no_audio sink;
            struct usb_endpoint_descriptor_no_audio source;
        } __attribute__((packed)) fs_descs, hs_descs;
    } __attribute__((packed)) descriptors = {
        .header = {
            .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
            .length = cpu_to_le32(sizeof descriptors),
            .fs_count = 3,
            .hs_count = 3,
        },
        .fs_descs = {
            .intf = {
                .bLength = sizeof descriptors.fs_descs.intf,
                .bDescriptorType = USB_DT_INTERFACE,
                .bNumEndpoints = 2,
                .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
                .iInterface = 1,
            },
            .sink = {
                .bLength = sizeof descriptors.fs_descs.sink,
                .bDescriptorType = USB_DT_ENDPOINT,
                .bEndpointAddress = 1 | USB_DIR_IN,
                .bmAttributes = USB_ENDPOINT_XFER_BULK,
                /* .wMaxPacketSize = autoconfiguration (kernel) */
                },
                .source = {
                    .bLength = sizeof descriptors.fs_descs.source,
                    .bDescriptorType = USB_DT_ENDPOINT,
                    .bEndpointAddress = 2 | USB_DIR_OUT,
                    .bmAttributes = USB_ENDPOINT_XFER_BULK,
                    /* .wMaxPacketSize = autoconfiguration (kernel) */
                },
            },
            .hs_descs = {
                .intf = {
                    .bLength = sizeof descriptors.fs_descs.intf,
                    .bDescriptorType = USB_DT_INTERFACE,
                    .bNumEndpoints = 2,
                    .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
                    .iInterface = 1,
                },
                .sink = {
                    .bLength = sizeof descriptors.hs_descs.sink,
                    .bDescriptorType = USB_DT_ENDPOINT,
                    .bEndpointAddress = 1 | USB_DIR_IN,
                    .bmAttributes = USB_ENDPOINT_XFER_BULK,
                    .wMaxPacketSize = cpu_to_le16(512),
                    },
                    .source = {
                        .bLength = sizeof descriptors.hs_descs.source,
                        .bDescriptorType = USB_DT_ENDPOINT,
                        .bEndpointAddress = 2 | USB_DIR_OUT,
                        .bmAttributes = USB_ENDPOINT_XFER_BULK,
                        .wMaxPacketSize = cpu_to_le16(512),
                        .bInterval = 1, /* NAK every 1 uframe */
                    },
                    },
    };

In c++ header file:

struct stDescriptorBody {
    usb_interface_descriptor source_sink_intf;
    usb_endpoint_descriptor_no_audio sink;
    usb_endpoint_descriptor_no_audio source;
    };__attribute__((packed))  

struct stDescriptor {
     usb_functionfs_descs_head header;
     stDescriptorBody fs_descs;
     stDescriptorBody hs_descs;
}__attribute__((packed)) ;

init function in implementation file:

stDescriptor initdescriptor(){

        stDescriptor descriptor;

        descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
        descriptor.header.length = cpu_to_le32(sizeof descriptor);
        descriptor.header.fs_count = 2;
        descriptor.header.hs_count = 2;

        descriptor.fs_descs.source_sink_intf.bLength = sizeof descriptor.fs_descs.source_sink_intf;
        descriptor.fs_descs.source_sink_intf.bDescriptorType = USB_DT_INTERFACE;
        descriptor.fs_descs.source_sink_intf.bNumEndpoints = 2;
        descriptor.fs_descs.source_sink_intf.bInterfaceClass =  USB_CLASS_VENDOR_SPEC;
        descriptor.fs_descs.source_sink_intf.iInterface = 1;

        descriptor.fs_descs.source.bDescriptorType = USB_DT_ENDPOINT;
        descriptor.fs_descs.source.bEndpointAddress =  1 | USB_DIR_OUT;
        descriptor.fs_descs.source.bLength =  sizeof descriptor.fs_descs.source;
        descriptor.fs_descs.source.bmAttributes = USB_ENDPOINT_XFER_BULK;
        /* .wMaxPacketSize = autoconfiguration (kernel) */

        descriptor.fs_descs.sink.bDescriptorType = USB_DT_ENDPOINT;
        descriptor.fs_descs.sink.bEndpointAddress =  1 | USB_DIR_IN;
        descriptor.fs_descs.sink.bLength =  sizeof descriptor.fs_descs.source;
        descriptor.fs_descs.sink.bmAttributes = USB_ENDPOINT_XFER_BULK;
        /* .wMaxPacketSize = autoconfiguration (kernel) */

        descriptor.hs_descs.source_sink_intf.bLength = sizeof descriptor.hs_descs.source_sink_intf;
        descriptor.hs_descs.source_sink_intf.bDescriptorType = USB_DT_INTERFACE;
        descriptor.hs_descs.source_sink_intf.bNumEndpoints = 2;
        descriptor.hs_descs.source_sink_intf.bInterfaceClass =  USB_CLASS_VENDOR_SPEC;
        descriptor.hs_descs.source_sink_intf.iInterface = 1;

        descriptor.hs_descs.source.bDescriptorType = USB_DT_ENDPOINT;
        descriptor.hs_descs.source.bEndpointAddress =  1 | USB_DIR_OUT;
        descriptor.hs_descs.source.bLength =  sizeof descriptor.hs_descs.source;
        descriptor.hs_descs.source.bmAttributes = USB_ENDPOINT_XFER_BULK;
        /* .wMaxPacketSize = autoconfiguration (kernel) */

        descriptor.hs_descs.sink.bDescriptorType = USB_DT_ENDPOINT;
        descriptor.hs_descs.sink.bEndpointAddress =  1 | USB_DIR_IN;
        descriptor.hs_descs.sink.bLength =  sizeof descriptor.hs_descs.source;
        descriptor.hs_descs.sink.bmAttributes = USB_ENDPOINT_XFER_BULK;
        /* .wMaxPacketSize = autoconfiguration (kernel) */

        return descriptor;
}
tzippy
  • 6,458
  • 30
  • 82
  • 151
  • 4
    I think it's compiler dependent too. If I recall correctly `__attribute__((packed))` is GNU specific. It might be worth to include compiler info too. I am not sure but I think the standards do not enforce any particular memory layouts when packing `struct` members. – luk32 Jan 28 '14 at 15:17
  • 2
    What is the question? BTW, a function to *initialize* an object is usually a *constructor*. – David Rodríguez - dribeas Jan 28 '14 at 15:17
  • 1
    Did you read this post: http://stackoverflow.com/questions/1429440/c-class-or-struct-compatiblity-with-c-struct – Brandin Jan 28 '14 at 15:31
  • 1
    For portability, don't rely on packed fields; read and write the fields as packed, let the compiler organize the internal memory for your structure. – Thomas Matthews Jan 28 '14 at 16:30
  • 3
    Never write structures directly to a file or communications channel. You should instead define a serialization format which nails down *everything* -- number of bytes for each field, endianness, padding, etc -- and write marshal/unmarshal functions that copy field by field, converting format, in and out a byte (`uint8_t`) buffer, then send *that*. – zwol Jan 28 '14 at 21:57

0 Answers0