【问题标题】:constant array in c - check if all elements are defined during compile timec中的常量数组-检查是否在编译时定义了所有元素
【发布时间】:2021-04-14 02:29:41
【问题描述】:

我正在 C 中寻找一种方法,在编译时检查是否设置了常量数组的所有元素。背景是,我想要一个带有命名行的查找表,它必须是完整的。

例子:

typedef enum [foo, bar, bla, max_value} rowNames;

static const uint32 LookupTable[max_value] =
{
    [foo] = 123,
    [bla] = 456, // oops, someone forgot to define the value for [bar]
}

retval = LookupTable[bar]; //this is to read out the value of the lookup table at a certain position

在此示例中,有人忘记定义数组元素 #1 [bar] 的值。我想确保在编译期间,所有值都已定义,错误会破坏构建。

当然,实际上表格会更大更复杂,但我认为这足以了解情况。尤其是后面要编辑枚举的时候,很有可能会出现枚举和表定义不一致的情况。

问候, 阿恩斯基

【问题讨论】:

  • 一种方式:提供用于初始化或设置数组值的宏或函数。
  • 好主意 kaylum,我可以尝试使用宏。只是担心,由于表的大小不是恒定的,使用可变参数宏创建枚举定义和表定义可能会变得复杂......

标签: arrays c compile-time


【解决方案1】:

只需对您的代码进行一些修改即可轻松完成。

将数组更改为static const uint32 LookupTable[],使其大小取决于初始化的项目数。然后在没有指定初始化器的情况下初始化数组,只需:

static const uint32 LookupTable[] =
{
  123, // foo
  456, // bla
  ...
};

现在您的标准 C 编译器可以使用编译时断言检查数组的完整性:

_Static_assert(sizeof LookupTable / sizeof *LookupTable == max_value, 
               "LookupTable wrong number of items");

编辑:

为了严格控制数据,可以使用“X 宏”技巧,它会创建非常丑陋的代码,但会将所有数据集中到源中的一个位置。在下面的示例中,所有数据信息都存储在宏 ARRAY_LIST 中:

#include <stdio.h>

#define ARRAY_LIST(X) \
  X(foo, 1)           \
  X(bar, 2)           \
  X(bla, 3)           \

typedef enum
{
  #define FOO_ENUM(name,val) name,
  ARRAY_LIST(FOO_ENUM)
  foo_n
} foo_t;

const int array[] =
{
  #define ARRAY_INIT(name,val) [name] = val,
  ARRAY_LIST(ARRAY_INIT)
};

_Static_assert(sizeof array / sizeof *array == foo_n, 
               "LookupTable wrong number of items");

int main (void)
{
  #define PRINT_ITEM(name,val) printf("%s: %d\n",#name, array[name]);
  ARRAY_LIST(PRINT_ITEM)
}

预处理器输出然后给出:

typedef enum
{
  foo, bar, bla,
  foo_n
} foo_t;

const int array[] =
{
  [foo] = 1, [bar] = 2, [bla] = 3,
};

_Static_assert(sizeof array / sizeof *array == foo_n,
               "LookupTable wrong number of items");

int main (void)
{
  printf("%s: %d\n","foo", array[foo]); 
  printf("%s: %d\n","bar", array[bar]); 
  printf("%s: %d\n","bla", array[bla]);
}

和程序输出:

foo: 1
bar: 2
bla: 3

【讨论】:

  • 谢谢。我同意,但要避免您必须在知道索引顺序的情况下初始化表。如果有人更改了 foo 和 bar 之间的顺序,您将再次获得错误的值,而不会注意到。手动保持顺序正确是一个很大的错误来源,特别是如果表变大并且将来发生变化......
  • @arnschi 要么严格控制代码,要么不控制。在允许完全重新排序的同时检查缺少的数组项没有多大意义。也有方法允许这样做,但它涉及“X 宏”,通常是一个丑陋的解决方案。
  • @arnschi 为了完整起见,我在答案中加入了 X 宏版本。由于代码变得丑陋,这是最后的手段,但在维护现有代码时它们可以很方便。
【解决方案2】:

由于您希望它在编译时发生,我认为您唯一的选择是创建一个静态代码分析器来执行此检查,并将其添加到您的工具链中,以便在每次构建时完成验证。

在运行时,只要将表定义更改为

static const uint32 LookupTable[] =
{
    /*[foo] = */123,
    /*[bla] = */456
}

这样,数组是自动调整大小的,并且可以使用sizeof来查看其中有多少条目,因此一旦有人更改了枚举,他们至少会在下次运行时得到运行时错误

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-08
    • 2013-12-15
    • 2022-01-10
    • 1970-01-01
    • 2012-04-27
    • 2023-03-31
    相关资源
    最近更新 更多