我正在尝试为数组数据冗余编写一个特殊的类型处理。其思想是在编译时全局定义和声明一个固定大小的数组,但每个声明的数组的大小不同。这就是想法:
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_t
和u
后缀整数常量。或者,如果您实际上在寻找负数,请使用-
而不是~
。
或者,作为最后的手段,您可以使用";"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";并且您的实用程序将输出您需要的任何声明。