【问题标题】:GCC Preproccesor macro to determine maximum size of multiple structsGCC Preproccesor 宏来确定多个结构的最大大小
【发布时间】:2014-01-26 04:26:17
【问题描述】:

有没有办法生成一个宏来产生数据类型列表的最大大小?

目标

typedef struct {
    uint8_t x;
} A;

typedef struct {
    uint16_t x;
} B;

typedef struct {
    uint8_t x[10];
} C;

#define sizeof_max(A,B,C)   //compiles to '10'

用例

公共数据段的不同值映射。

typedef union {
    uint8_t array[sizeof_max(A,B,C)];
    A iso_hugenum_a;
    B ext_a0;
    C ext_a1;  //and someday down the road 'D' may also get added
} DATA_SEG;

这适用于设备实现基本协议 ISO_HUGENUM_A 的嵌入式应用程序。设备还必须支持此协议 EXT_A0、EXT_A1、EXT_B0 的扩展。哎呀,在这种情况下,EXT_C0 很有可能出现在路上(糟糕)!

备注

这里的主要目标是让顶级系统以可扩展且安全的方式了解数据段的大小。当您需要作为数组时,很容易说 'cast as array'。但是

  • 在系统级别(谁不提供有关协议的 eff)对该数据段进行读取、写入和检查(例如 crc)

  • 2 年后,'EXT_C0' 可能会出现。我想给继承我的代码的可怜的灵魂留下一些在 EXT_C0 增长数据段时不会中断的东西

我希望有一个解决方案,但还没有找到。有任何想法吗?所有尺寸都将由预处理器生成,因此它似乎是宏的理想候选者。

-贾斯汀

【问题讨论】:

  • 为什么你不能只使用sizeof 一些union - 就像你的DATA_SEG 没有 array
  • 这不只是union 的正常用例吗?
  • 删除了 C++ 标签;谢谢。
  • 依赖数组也可能导致问题 - 较小的结构会导致您的数组包含您可能会意外读取的数据,因此无论读取什么层,它仍然需要聪明。你应该坚持工会..
  • 是的,这似乎是一个常见的联合用例。我最终可能会删除数组成员。然而,在这个协议的上下文以及系统如何执行 iso_hugenum_a 的情况下,数组访问是我想要的主要功能。

标签: c gcc macros embedded


【解决方案1】:

以下宏定义完全满足您的要求:

#define sizeof_max(s1,s2,s3) sizeof( union{s1 a; s2 b; s3 c; })

对于您的示例结构如下:

size_t s = sizeof_max( A,B,C ) ;

导致s = 10。

当然,当您想作为字节数组访问时,您可以省略数组成员,只需将 DATA_SEG 对象地址转换为 uint8_t*

DATA_SEG x ;
uint8_t* array = (uint8_t*)&x ; 

这将允许DATA_SEG 在必要时添加更多结构,而无需更改宏 - 更安全且更易于维护。


添加

另一种可能性是将专门的解释与字节覆盖区分开来:

typedef union 
{
    A iso_hugenum_a;
    B ext_a0;
    C ext_a1;  
    D added_someday ;
} DATA_SEG_U;

typedef union 
{
    uint8_t array[sizeof(DATA_SEG_U)];
    DATA_SEG_U data_seg ;
} DATA_SEG ;

【讨论】:

  • "//未来某天'D'也可能会被添加":OP 要求进行概括,而不仅仅是针对 3 名成员的情况。跨度>
  • @pablo1977:我得考虑一下。
  • 我只是在想这个;该死的克里福德!非常优雅的解决方案。谢谢。
  • 更正:array[sizeof(DATA_SEG_U)]
  • 是的,需要 sizeof。
【解决方案2】:

将可变参数宏与多级预处理相结合可以工作 -

这实现了“最多 5 个输入”的预期目标。

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N

#define VA_NUM_ARGS(...)                 VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define macro_dispatcher__(func,nargs)   func ## nargs
#define macro_dispatcher_(func, nargs)   macro_dispatcher__(func, nargs)
#define macro_dispatcher(func, ...)      macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))

#define sizeof_max(...) macro_dispatcher(sizeof_max, __VA_ARGS__)(__VA_ARGS__)

#define sizeof_max1(a)         (sizeof(a))
#define sizeof_max2(a,b)       (sizeof(a)>sizeof(b)?sizeof(a):sizeof(b))
#define sizeof_max3(a,b,c)     sizeof_max2(sizeof_max2(a,b), c)
#define sizeof_max4(a,b,c,d)   sizeof_max2(sizeof_max3(a,b,c),d)
#define sizeof_max5(a,b,c,d,e) sizeof_max2(sizeof_max4(a,b,c,d),e)

这适用于 GCC/C99。这是问题的“一个”解决方案,我在这里发帖是因为我从中学到了很多东西,并想分享它。话虽如此,请阅读最后的免责声明:)。

参考文献

这里的 efesx 论坛的 'rmn' 提供了 macro_dispatcher() 的使用:

在函数名中添加 fcn# 也有描述:

当然,这里有一些 GCC 可变参数宏页面:

示例

typedef union {
    uint8_t array[sizeof_max(A,B,C)];  //array is of size 10.
    A iso_hugenum_a;
    B ext_a0;
    C ext_a1; 
} DATA_SEG;

细分

您可以在“main.c”中尝试此代码并使用“gcc -E main.c”进行编译以观察宏:

int main (void) {
    uint8_t rslt;

    //preprocs to 'rslt=C;'
    rslt = VA_NUM_ARGS_IMPL(A,B,C,A,B,C,A);

    //preprocs to 'rslt=3'
    rslt = VA_NUM_ARGS(A,B,C);

    //preprocs to 'rslt=maxN'
    rslt = macro_dispatcher__(max, N);

    //preprocs to 'rslt=macro_dispatcher_(max, N);'
    rslt = macro_dispacther_(max, N);

    //preprocs to 'rslt=max3;'
    rslt = macro_dispatcher(max, X, Y, Z);

    //preprocs to 'sizeof_max1(A)/max2(A,B)/max3(A,B,C)'
    rslt = sizeof_max(A);
    rslt = sizeof_max(A,B);
    rslt = sizeof_max(A,B,C);


    //Breakdown:
    //sizeof_max(A,B,C);
    //macro_dispatcher(sizeof_max, __VA_ARGS__)(__VA_ARGS__)
    //macro_dispatcher_(sizeof_max, 3)(__VA_ARGS__)
    //macro_dispatcher__(sizeof_max,3)(__VA_ARGS__)
    //
    //Result:
    //sizeof_max3(__VA_ARGS__)
    //sizeof_max3(A,B,C)
    rslt = sizeof_max(A,B,C);

    return 0;
}

(免责声明) 更简单、更安全总是胜出。因此,我很可能会选择最接近克利福德答案的东西。我没有必要玩一些可爱的把戏,在路上“咬”别人。

【讨论】:

    猜你喜欢
    • 2015-11-26
    • 2011-02-14
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    相关资源
    最近更新 更多