在C语言中编译时如何找到100个结构体中最大的尺寸

7

我有100个结构体,看起来像这样:

struct s00 { char   data[30]; };
struct s01 { char   data[30]; };
struct s02 { int    data[10]; };
struct s03 { double data[5];  };
struct s04 { float  data[20]; };
struct s05 { short  data[15]; };
struct s06 { char   data[7];  };
struct s07 { int    data[19]; };
struct s08 { double data[11]; };
struct s09 { float  data[5];  };
struct s10 { char   data[52]; };
//...
struct s99 { char   data[12]; };

typedef struct s00 s00;
typedef struct s01 s01;
typedef struct s02 s02;
//...
typedef struct s99 s99;

我希望在编译时找到这些结构体中最大的sizeof。我尝试使用类似于这样的比较宏:
 #define LARGER(a, b) ((a) > (b) ? (a) : (b))

然后使用此来构建最终定义,其中将包含结果:
#define MAX_SIZEOF (LARGER(sizeof(s00), \
                    LARGER(sizeof(s01), \
                    LARGER(sizeof(s02), \
                    LARGER(sizeof(s03), \
                    LARGER(sizeof(s04), \
                    LARGER(sizeof(s05), \
                    LARGER(sizeof(s06), \
                    LARGER(sizeof(s07), \
                    LARGER(sizeof(s08), \
                    LARGER(sizeof(s09), \
                    LARGER(sizeof(s10), \
                    //...
                    sizeof(s99))) /*...*/ ))

然而,编译器空间不足:
错误C1060 编译器堆栈空间不足
这很合理,因为这个 #define 必须跟踪许多数字,因为它只是替换文本。具体来说,MAX_SIZEOF 中找到的整数数量是指数级的,可以描述为:

number of numbers

其中x等于涉及的结构体数量。假设一个整数占用4字节,编译器需要分配30.4个十的21次方字节来计算此宏(如果我的计算正确的话)。我的系统最多只能处理17个结构体(786430个数字,3.14兆字节)。

我不确定如何在C中找到高效的解决方案。

在C++中,我可以很容易地使用constexpr实现这一点,而且没有任何编译问题:

constexpr size_t LARGER(size_t a, size_t b) {
    return a > b ? a : b;
}
constexpr size_t MAX_SIZEOF() {
return 
    LARGER(sizeof(s00), \
    LARGER(sizeof(s01), \
    LARGER(sizeof(s02), \
    LARGER(sizeof(s03), \
    LARGER(sizeof(s04), \
    LARGER(sizeof(s05), \
    LARGER(sizeof(s06), \
    LARGER(sizeof(s07), \
    LARGER(sizeof(s08), \
    LARGER(sizeof(s09), \
    LARGER(sizeof(s10), \
    //...
    sizeof(s99))/*...*/)));

但是,我必须在这里仅使用C语言。...感谢任何想法!


3
为什么你想要这样做? - edition
@Edition 我正在通过套接字(CSFML UDP套接字)发送许多不同的结构体。由于这些套接字使用固定大小的缓冲区进行接收,我想找到最大值,以避免缓冲区越界。我通过动态分配缓冲区来避免这个问题,但现在我想提高程序的性能。 - Stack Danny
c++如何实现constexpr,在编译时评估您在c中尝试的内容,而不发出任何警告声? - izac89
@user2162550 嗯,我想编译器确实在评估每个三元运算符,而不仅仅是在通过层级时替换文本。 - Stack Danny
或者说,预处理器正在评估它。 - Stack Danny
2个回答

18

你可以声明一个包含所有结构体的联合体

union allstructs {
    struct s00 s00val;
    struct s01 s01val;
    /* ... */
    struct s99 s99val;
}

并获取联合的大小

sizeof(union allstructs)

当您想通过网络传输结构时,还应考虑结构的打包/填充、字节顺序和浮点实现。


我本来想使用 max() 宏语句,但这种方式更加优美...所以 +1。 - Spektre
@Spektre 我仍然很好奇看看那会是怎样的工作。 - Stack Danny
@StackDanny 我把那种方法添加为答案。 - Spektre

1

正如我在其他答案中提到的那样,其他答案更好,但按照要求,这对我有用(在AtmelStudio 6.2 C编译器模式下):

typedef struct { char   data[30]; }s00;
typedef struct { char   data[30]; }s01;
typedef struct { int    data[10]; }s02;
typedef struct { double data[5];  }s03;
typedef struct { float  data[20]; }s04;
typedef struct { short  data[15]; }s05;
typedef struct { char   data[7];  }s06;
typedef struct { int    data[19]; }s07;
typedef struct { double data[11]; }s08;
typedef struct { float  data[5];  }s09;
typedef struct { char   data[5]; }s10;
typedef struct { char   data[5]; }s11;
typedef struct { char   data[5]; }s12;
typedef struct { char   data[5]; }s13;
typedef struct { char   data[5]; }s14;
typedef struct { char   data[5]; }s15;
typedef struct { char   data[2]; }s16;
typedef struct { char   data[5]; }s17;
typedef struct { char   data[5]; }s18;
typedef struct { char   data[5]; }s19;
typedef struct { char   data[3]; }s20;
typedef struct { char   data[5]; }s21;
typedef struct { char   data[5]; }s22;
typedef struct { char   data[5]; }s23;
typedef struct { char   data[5]; }s24;
typedef struct { char   data[5]; }s25;
typedef struct { char   data[5]; }s26;
typedef struct { char   data[4]; }s27;
typedef struct { char   data[5]; }s28;
typedef struct { char   data[5]; }s29;
typedef struct { char   data[5]; }s30;
typedef struct { char   data[5]; }s31;
typedef struct { char   data[5]; }s32;
typedef struct { char   data[5]; }s33;
typedef struct { char   data[5]; }s34;
typedef struct { char   data[5]; }s35;
typedef struct { char   data[5]; }s36;
typedef struct { char   data[5]; }s37;
typedef struct { char   data[5]; }s38;
typedef struct { char   data[99];}s39;

#define sm(a0,a1) (sizeof(a0)>sizeof(a1)?sizeof(a0):sizeof(a1))
#define mm(a0,a1) (a0>a1?a0:a1)
#define s_10 sm(sm(sm(sm(sm(sm(sm(sm(sm(s00,s01),s02),s03),s04),s05),s06),s07),s08),s09)
#define s_20 sm(sm(sm(sm(sm(sm(sm(sm(sm(s10,s11),s12),s13),s14),s15),s16),s17),s18),s19)
#define s_30 sm(sm(sm(sm(sm(sm(sm(sm(sm(s20,s21),s22),s23),s24),s25),s26),s27),s28),s29)
#define s_40 sm(sm(sm(sm(sm(sm(sm(sm(sm(s30,s31),s32),s33),s34),s35),s36),s37),s38),s39)
const int s_size=mm(mm(mm(s_10,s_20),s_30),s_40);

单行版本不起作用,但如果我将值分成多行(s_10,s_20,...),那么我可以使用甚至40个struct并获得正确的输出99。由于我太懒了,所以没有尝试更多... 我认为这不是分配问题,而更像预处理器每行长度的最大限制...
输出值为s_size,也可以是#define...

感谢您的提交!分开处理是个好主意~ - Stack Danny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接