从宏函数中提取 __VA_ARGS__ 时初始化数组

Initialising an array while extracting __VA_ARGS__ from a macro function

我正在尝试为数组数据冗余编写特殊类型处理。这个想法是在编译时全局定义和声明一个固定大小的数组,但每个声明的数组的大小都不同。这是想法:

array[N] = { el1, el2, el3, ..., elN };

起初,我使用了以下有效的语法:

#define ARRAY_DEFDEC(name, size, ...) \
    int arr_##name[size] = { __VA_ARGS__ }

当我使用这个宏时,我得到了预期的结果:

// C code
ARRAY_DEFDEC(array_test, 7, 1, 2, 3, 4, 5, 6, 7);
// Preprocessed
int arr_array_test[7] = { 1, 2, 3, 4, 5, 6, 7 };

现在,对于我遇到的问题,不知道是否可以解决。在执行此操作时,我还需要创建第二个数组,所有值都将被反转(使用 ~ 运算符或(0 - 元素 + 1))。我试过 ~VA_ARGS,但自然地,它只会改变第一个元素(在上面的例子中 arr_array_test 我会得到 -2, 2, 3 , 4, 5, 6, 7).

我有一个解决方案可以执行以下操作:

#define ARRAY_DEFDEC(name, size, ...)
    int arr_##name[2*size] = { __VA_ARGS__ };

然后使用方法如下:

ARRAY_DEFDEC(test, 7, 1, 2, 3, 4, 5, 6, 7, ~1, ~2, ~3, ~4, ~5, ~6, ~7)

这需要更改相当多的逻辑,并且用户需要知道除了初始化元素外,还需要提供二进制逆,所以我不太喜欢这样做。

此刻我假设参数 size 与 size(__VA_ARGS__).

具有相同的大小

数组旨在用作全局定义(因为它们需要被多个函数访问)。

注意:由于是嵌入式系统,不能包含外部库。系统上没有单一的标准库(例如 stdio、stdarg、stdint 等)。这也进一步限制了选项。使用的标准是 C99,编译器来自 Green Hill Software。

我觉得解决这个问题的方法是那些由两打 sub-macros 组成的宏之一,这些解决方案总是让我决定以其他方式解决问题。宏可以做一些事情,但它们不是完整的编程语言,因此它们的功能有限。

我只想编写一个小实用程序将原始数据转换为 C 代码,然后#include。您可以将该实用程序作为编译过程的一部分进行编译,然后使用它来编译其余代码。因此,您的 data.txt 可以只说“test 1 2 3 4 5 6 7”,您的实用程序将输出您需要的任何声明。

Is it possible somehow to apply the ~ operator to all VA_ARGS?

不,您必须根据参数数量重载宏。

从允许在每个参数上应用函数 f 的通用 FOREACH 宏开始,这里是最多 3 个参数的示例:

#define FOREACH_1(f, x)  f(x)
#define FOREACH_2(f, x, ...)  f(x) FOREACH_1(f,__VA_ARGS__)
#define FOREACH_3(f, x, ...)  f(x) FOREACH_2(f,__VA_ARGS__)
#define FOREACH_N(_3,_2,_1,N,...) FOREACH_##N
#define FOREACH(f, ...)  FOREACH_N(__VA_ARGS__,3,2,1)(f, __VA_ARGS__)

然后您将定义数组并定义第二个倒置数组。

// note the comma
#define INVERT(x)  ~x,
#define ARRAY_DEFDEC(name, ...) \
    int arr_##name[] = { __VA_ARGS__ }; \
    int secondarr_##name[] = { FOREACH(INVERT, __VA_ARGS__) };

ARRAY_DEFDEC(name, 1, 2, 3)

比可变参数宏 更好的解决方案是简单地 #define 每个数组不同的初始化列表。

即:

#define ARRAY_TEST_7 { 1, 2, 3, 4, 5, 6, 7 }

int arr_array_test[] = ARRAY_TEST_7;

这是常见的做法。与使用 MAGIC_MACRO(my_variable, stuff); 发明您的私人 project-specific 宏语言相反,这是非常糟糕的做法。

可选择添加如下内容:

static_assert(sizeof arr_array_test/sizeof *arr_array_test == expected_size,
              "error message");

并求解反转值:

#define ARRAY_TEST_7     {  1,  2,  3,  4,  5,  6,  7 }
#define ARRAY_TEST_7_INV { ~1, ~2, ~3, ~4, ~5, ~6, ~7 }

请注意,按位反转普通 int 可能不是任何目的的最佳主意。 (它不给出 2 的补码,而是 1 的补码)您很可能应该使用 uint32_tu 后缀整数常量。或者,如果您实际上是在寻找负数,请使用 - 而不是 ~.


或者,作为最后的手段,您可以使用“X-macros”来减少代码重复。它们相当难读,但至少在某种程度上符合行业标准,因此习惯于阅读它们的程序员可以分辨出它们的作用。与世界上 没有 C 程序员知道也不想学习的秘密私有宏语言相反。

#include <inttypes.h>
#include <stdio.h>

#define ARRAY3_VALUES(X)    \
/*  value */                \
  X(1)                      \
  X(2)                      \
  X(3)                      \

#define ARRAY7_VALUES(X)    \
/*  value */                \
  X(1)                      \
  X(2)                      \
  X(3)                      \
  X(4)                      \
  X(5)                      \
  X(6)                      \
  X(7)                      \


#define ARRAY_ITEM_INIT(val) (val),
#define ARRAY_ITEM_INIT_INV(val) (~(val)),

#define UINT32_ARRAY_DECLARE(size) \
  const uint32_t array##size[size] =  { ARRAY##size##_VALUES(ARRAY_ITEM_INIT) }

#define UINT32_ARRAY_DECLARE_INV(size) \
  const uint32_t array##size##_inv[size] =  { ARRAY##size##_VALUES(ARRAY_ITEM_INIT_INV) }



int main (void)
{
   UINT32_ARRAY_DECLARE(3);       // declares array3 with a given initializer list
   UINT32_ARRAY_DECLARE_INV(3);   // declares array3_inv with same initializer list but inverted
   UINT32_ARRAY_DECLARE(7);       // similar but some 7 item version
   UINT32_ARRAY_DECLARE_INV(7);

   for(size_t i=0; i<3; i++)
     printf("%"PRIx32 "%c", array3[i], i==2?'\n':',');

   for(size_t i=0; i<3; i++)
     printf("%"PRIx32 "%c", array3_inv[i], i==2?'\n':',');

   for(size_t i=0; i<7; i++)
     printf("%"PRIx32 "%c", array7[i], i==6?'\n':','); 

   for(size_t i=0; i<7; i++)
     printf("%"PRIx32 "%c", array7_inv[i], i==6?'\n':',');
}

输出:

1,2,3
fffffffe,fffffffd,fffffffc
1,2,3,4,5,6,7
fffffffe,fffffffd,fffffffc,fffffffb,fffffffa,fffffff9,fffffff8