【问题标题】:Is it possible to pad a C/C++ structure to a fixed size using a compile time calculation?是否可以使用编译时计算将 C/C++ 结构填充到固定大小?
【发布时间】:2021-02-05 16:22:38
【问题描述】:

是否可以在编译时计算结构中所需的填充数组的大小,以使结构最终成为每个确定的大小。那就是我想做这样的事情(我知道这行不通)

#define APPDESCTARGETSIZE       256         // Target size for the App Desc Structure

// Structure member size of
#define msizeof(type, member) sizeof(((type *)0)->member)

// Size of padding arrary
#define padsize     (APPDESCTARGETSIZE - (offsetof(custom_app_desc_t, pad) + msizeof(custom_app_desc_t, tail)))

/**  * @brief Description about application.  */ 
typedef struct {
    uint8_t   header[16];
    char      progname[16];
    char      boardname[16];
    uint8_t   chipsize;
    uint8_t   version_maj;
    uint8_t   version_min;
    uint8_t   version_iss;
    uint8_t   pad[padsize];
    uint8_t   tail[16]; 
 } custom_app_desc_t;

我可以通过如下的手动计算来解决,但编译器为我做数学会很好:

#define padsize     (APPDESCTARGETSIZE - 68)

注意,在这种情况下,重要的是 pad 出现在 'tail' 成员之前。

【问题讨论】:

  • 您应该决定是在 C(基于宏的解决方案)还是 C++(基于模板和 constexpr 的解决方案)中执行此操作
  • 您想使用/访问pad 字段吗?请edit回答您的问题。也许你可以使用联合。
  • 假设 C 和宏等
  • 您会收到如下错误:lib\RR_OTA_Update\src/custAppDesc.h:46:73: 错误:“struct custom_app_desc_t”没有名为“pad”的成员 const size_t padsize = (APPDESCTARGETSIZE - offsetof (custom_app_desc_t, pad) + msizeof(custom_app_desc_t, tail));
  • @KamilCuk :你能说明在哪里使用 offsetof() 吗?我在尝试中遇到了上述编译器错误。因为结构没有在定义之前声明。因此捕获 22 !!

标签: c++ c


【解决方案1】:

解决此问题的一种方法是使用union

struct {
    union {
        struct {
            // this is your structure, without the last element
        };
        char _reserved[APPDESCTARGETSIZE - 16]; // exclude the last tail element
    };
    char tail[16]; // the tail is outside of the padding
};

【讨论】:

  • 你能解释一下为什么最后一个元素不包含在联合中吗?
  • 您可以不使用内部结构的名称,以便可以直接访问其成员。
  • 并集的右大括号后缺少分号。
  • _data 不需要
  • @TanveerBadar:按照问题的要求,它位于填充之后。
【解决方案2】:

最简单的 IMO 方法是包装到另一个结构中。

#define APPDESCTARGETSIZE       256  
#define TAILSIZE    16
#define TAILTYPE    uint8_t

typedef struct {
    struct internal{
        uint8_t   header[16];
        char      progname[16];
        char      boardname[16];
        uint8_t   chipsize;
        uint8_t   version_maj;
        uint8_t   version_min;
        uint8_t   version_iss;
    }fields;
    uint8_t   pad[APPDESCTARGETSIZE - sizeof(struct internal) - sizeof(TAILTYPE) * TAILSIZE];
    TAILTYPE   tail[TAILSIZE]; 
 } custom_app_desc_t;

或作为_Blindy(但使用匿名结构)

#define APPDESCTARGETSIZE       256  
#define TAILSIZE    16
#define TAILTYPE    uint8_t

typedef struct {
    union {
        struct {
            uint8_t   header[16];
            char      progname[16];
            char      boardname[16];
            uint8_t   chipsize;
            uint8_t   version_maj;
            uint8_t   version_min;
            uint8_t   version_iss;
        };
        struct {
            uint8_t _dummy[APPDESCTARGETSIZE - sizeof(TAILTYPE) * TAILSIZE];
        };
    };
    TAILTYPE   tail[TAILSIZE]; 
 } custom_app_desc_t;

【讨论】:

    【解决方案3】:

    使用未命名的联合和结构成员,您可以根据自己的目的控制布局:

    #define APPDESCTARGETSIZE  256    // Target size for the App Desc Structure
    
    /**  * @brief Description about application.  */ 
    typedef struct {
        union {
            struct {
                uint8_t   header[16];
                char      progname[16];
                char      boardname[16];
                uint8_t   chipsize;
                uint8_t   version_maj;
                uint8_t   version_min;
                uint8_t   version_iss;
            };
            uint8_t   pad0[APPDESCTARGETSIZE - 16];
        };
        uint8_t   tail[16]; 
    } custom_app_desc_t;
    

    您可以像访问custom_app_desc_t 的成员一样访问成员:

        custom_app_desc_t obj;
        get_app_desc(&obj);
        printf("progname: %s\n", obj.progname);
    

    这种方便的语法技巧称为匿名联合匿名结构

    匿名联合的大小是其每个成员的最大大小,即:具有您的命名成员的结构和字节数组pad0。 由于命名成员的数量小于APPDESCTARGETSIZE-16 字节,因此联合大小正好是APPDESCTARGETSIZE-16,这是练习的目标。

    如果您需要访问填充字节,您可以在内部结构的末尾添加一个额外的成员uint8_t pad[1];

    如果tail部分不是一个简单的字节数组,你需要为它定义一个结构类型并减去它的大小而不是16。

    【讨论】:

    • @0___________:哎呀,我误读了规范。现已修复。
    • 如果我想要某种通用解决方案,我不会使用硬编码 16。
    猜你喜欢
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    • 2011-01-01
    • 2020-11-27
    • 1970-01-01
    相关资源
    最近更新 更多