This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Confusing definition

C:\Nordic Semiconductor\nrf51_sdk_v4_4_1_31827\nrf51822\Include\ble\softdevice\ble_gatts.h


typedef struct {
  uint16_t     handle;    /**< Attribute Handle. */
  uint8_t       op;          /**< Type of write operation, see @ref BLE_GATTS_OPS. */
  ble_gatts_attr_context_t    context;     /**< Attribute Context. */
  uint16_t      offset;      /**< Offset for the write operation. */
  uint16_t      len;          /**< Length of the incoming data. */
  uint8_t       data[1];    /**< Incoming data, variable length. */
} ble_gatts_evt_write_t;

My question is how to interpret the element data[1]? Is it just uint8_t *data(C-wise it is)? If so why is it defined in such a way? Especially with the size of the data array as one with the following comment about its variable length which all together makes this definition very confusing.

Thanks.

Parents
  • One more thing: if array has predefined length then it needs to be less than uint16_t len; /* Length of the incoming data. */.

    The way I see the intention of the developer is:

    typedef union {
    unit8_t event_x[1];  /* event x message */
    uint16_t event_y[2];/* event y message */
    void *event_z; /* event z message */
    /* more event messages if necessary */
    } event_message_t; /* union will have the size of known largest message */
    struct
    {
    ...
    uint16_t len; /* Length of the incoming data; len <= sizeof(event_message_t); */
    event_message_t data;
    }ble_gatts_evt_write_t;
    
    
Reply
  • One more thing: if array has predefined length then it needs to be less than uint16_t len; /* Length of the incoming data. */.

    The way I see the intention of the developer is:

    typedef union {
    unit8_t event_x[1];  /* event x message */
    uint16_t event_y[2];/* event y message */
    void *event_z; /* event z message */
    /* more event messages if necessary */
    } event_message_t; /* union will have the size of known largest message */
    struct
    {
    ...
    uint16_t len; /* Length of the incoming data; len <= sizeof(event_message_t); */
    event_message_t data;
    }ble_gatts_evt_write_t;
    
    
Children
  • This isn't really feasible, as the value within this array can be any data, of any format. If you look into the on-air operations, there is no requirement that this data is structured in any way. Also, even if the characteristic value have a certain structure, the data used here can be offset, and hence have no structure after all. A variable sized array is therefore the only reasonable option as far as I can see.

  • Sorry again...How can one implement variable length? Byte by byte with the offset 1? Why then have member len? I have serious trouble understanding your point. Yes one can create ble_gatts_evt_X_write_t, ble_gatts_evt_Y_write_t, ble_gatts_evt_Z_write_t and so on and in this case each event will have its own constant not variable length. Or use ble_gatts_evt_write_t with the length 1 and use offset if more than one byte is required. Or I'm totally misunderstanding what those types are trying to achieve...

    Lets say I have LED which is using event write to turn it on and off(bool) and I have a DAC and need to set it up(uint16_t). How to manage this combination?

    Thanks!

  • Beware that you are never expected to initialize a struct of this type, as it's only an event structure, initialized by the softdevice to notify you as an application of an incoming Write Command / Request.

    If you are to initialize some other struct employing the same concept, you would manually have to make sure to initialize it with appropriate size for the data you want to fit.

    After checking a little more, it's apparently known as the "struct hack", and explained in more detail here, including how to initialize such struct: http://c-faq.com/struct/structhack.html

  • I'm trying to response as soon as I can to beat the time difference, so excuse me it is little bit aster 6 in the morning here... Your said:"Beware that you are never expected to initialize a struct of this type, as it's only an event structure". There is option static winch forces a compiler to initialize memory with 0 and yes this is static and not dynamic memory. That is exactly what SD is doing. BTW please mention the exact type: we're talking about quite few in this discussion.

    http://c-faq.com/struct/structhack.html char data[] is defined in C99 and not in C89 as you said before. char data[1] is defined in both standards. Yet it is very tastefulness to use [1] as commenting it as variable length. In this case adding extra pointer and all hassles which come with it is much better for readability. It worth it from my stand point especially if this code is published for other people reading/using. Don't see any issues with static allocation by SD array of MAX_MTU size and application casting it to the any type it knows and needs.

    Thank you for coming back to this discussion.

  • I'm not sure I understand what you mean about static declarations. My point was that application code should not need to ever declare a variable of this type (although possibly a pointer to one).

    Unfortunately, I don't think we'll ever fully agree on what is most readable and not here, but I've added a request internally to consider this question again, either adding a more extensive comment or possibly also change the declaration to [], to indicate that the length is in fact unknown at compile time.

Related