sizeof(enum) 未按预期运行

Posted

技术标签:

【中文标题】sizeof(enum) 未按预期运行【英文标题】:sizeof(enum) not behaving as expected 【发布时间】:2021-12-01 11:51:23 【问题描述】:

我正在使用 gcc 为 32 位 arm mcu 编译以下代码。

    static int test_sanity_enum_size(void)

    enum smallchoices  sa, sb, sc ;
    enum medchoices  ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml ;
    enum largechoices 
        a01, b01, c01, d01, e01, f01, g01, h01, i01, j01,
        a02, b02, c02, d02, e02, f02, g02, h02, i02, j02,
        a03, b03, c03, d03, e03, f03, g03, h03, i03, j03,
        a04, b04, c04, d04, e04, f04, g04, h04, i04, j04,
        a05, b05, c05, d05, e05, f05, g05, h05, i05, j05,
        a06, b06, c06, d06, e06, f06, g06, h06, i06, j06,
        a07, b07, c07, d07, e07, f07, g07, h07, i07, j07,
        a08, b08, c08, d08, e08, f08, g08, h08, i08, j08,
        a09, b09, c09, d09, e09, f09, g09, h09, i09, j09,
        a10, b10, c10, d10, e10, f10, g10, h10, i10, j10,
        xxx ;

    /* Enum size */
    if (!TEST_size_t_eq(sizeof(enum smallchoices), sizeof(int))
        || !TEST_size_t_eq(sizeof(enum medchoices), sizeof(int))
        || !TEST_size_t_eq(sizeof(enum largechoices), sizeof(int)))
        return 0;
    return 1;

函数返回 0。虽然所有 3 个枚举只有很少的元素,所以默认情况下枚举类型将是 int 类型,所以我希望函数返回 1 但它返回 0。我需要修改测试条件还是枚举数组,以便函数返回 1?

【问题讨论】:

您为什么不直接打印出sizeof 值来自己找出它是什么?您可能会发现它比 int 小。 这能回答你的问题吗? What is the size of an enum in C? 如果您无法在目标处理器上打印,this answer 提供了有关从 GCC 中提取编译时表达式值的信息。比如把里面的offsetof(struct A, b)替换成sizeof(enum smallchoices) 【参考方案1】:

你写...

虽然所有 3 个枚举只有很少的元素,所以默认情况下枚举类型将是 int 类型

...但是虽然enum 类型是integer 类型,但不能确定它们与int 兼容。相反,语言规范是这样说的:

每个枚举类型都应与char兼容,这是一个有符号整数 类型,或无符号整数类型。类型的选择是 实现定义,但应能够表示 枚举所有成员的值。

(C17 6.7.2.2/4)

您的enums 中没有一个常量或值太大而无法与char 兼容的常量,因此所有类型都可供实现选择。

我是否需要修改测试条件或枚举数组,以便 函数返回 1?

那里没有数组,但我想你的意思是枚举定义中的枚举数列表。没有办法确保您的 enum 类型在每个 C 实现中都与 int 兼容,但是通过指定一个范围,您很有可能获得 int-size 枚举的枚举值至少需要这么大的表示。例如,

    enum smallchoices  sa, sb, sc = INT_MAX ;
    enum medchoices  ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml = INT_MAX ;
    enum largechoices 
        a01, b01, c01, d01, e01, f01, g01, h01, i01, j01,
        a02, b02, c02, d02, e02, f02, g02, h02, i02, j02,
        a03, b03, c03, d03, e03, f03, g03, h03, i03, j03,
        a04, b04, c04, d04, e04, f04, g04, h04, i04, j04,
        a05, b05, c05, d05, e05, f05, g05, h05, i05, j05,
        a06, b06, c06, d06, e06, f06, g06, h06, i06, j06,
        a07, b07, c07, d07, e07, f07, g07, h07, i07, j07,
        a08, b08, c08, d08, e08, f08, g08, h08, i08, j08,
        a09, b09, c09, d09, e09, f09, g09, h09, i09, j09,
        a10, b10, c10, d10, e10, f10, g10, h10, i10, j10,
        xxx = INT_MAX ;

原则上,一个实现可以使用某种压缩表示,但我不知道有任何实现会如此长以节省空间。

【讨论】:

【参考方案2】:

枚举是有问题的,因为枚举类型,即变量本身,可以具有实现定义的大小,只要它大到足以容纳所有指定的项目。 enum smallchoices sa, sb, sc ; 之类的东西可以放入 8 位整数类型,因此嵌入式系统编译器特别将其优化到 8 位是很常见的。所以你的“健全性测试”是错误的,它与 C 标准相冲突。

另一方面,枚举常量,这些:sa, sb, sc,保证始终是 int 类型。

因此,如果您需要具有固定大小枚举(或仅 32 位对齐块)的可移植代码,那么您不应该使用 enum 来进行实际存储,而是使用来自 stdint.hintn_t 类型之一(可能uint32_t 在这种情况下)。您仍然可以使用 typedef enum 等创建常量列表,但如果确定性大小很重要,请不要使用该类型进行存储。

【讨论】:

以上是关于sizeof(enum) 未按预期运行的主要内容,如果未能解决你的问题,请参考以下文章

PostAsJsonAsync 未按预期运行

UIAlertController 未按预期运行

C#“继续”未按预期运行

多线程未按预期运行

NSPredicate - 包含未按预期运行

QRegExp 未按预期运行