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



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

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(。

  • 是否可以以某种方式将~运算符应用于所有__VA_ARGS__

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

#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)

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

此时此刻,我假设参数大小与大小(__VA_ARGS__(相同。

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

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

是否可以以某种方式将~运算符应用于所有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);发明私人的、特定于项目的宏语言相反,这是一种非常糟糕的做法。

可选择添加以下内容:

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宏";以减少代码重复。它们很难阅读,但至少是某种行业标准,这样习惯阅读它们的程序员就可以知道它们在做什么。与世界上没有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

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

我只想写一个小实用程序,将原始数据转换为C代码,然后#包括它。您可以将实用程序作为编译过程的一部分进行编译,然后使用它来编译其余的代码。所以你的data.txt可以说";测试1 2 3 4 5 6 7";并且您的实用程序将输出您需要的任何声明。

相关内容

  • 没有找到相关文章

最新更新