【发布时间】:2021-08-10 20:03:21
【问题描述】:
我正在为 stm32l0 微控制器编写一些程序。 我将一些数组定义为全局变量:
volatile uint32_t synth_counter [N_CHANNELS];
volatile uint32_t synth_pitch [N_CHANNELS];
volatile uint32_t synth_envelope [N_CHANNELS];
volatile int_fast8_t synth_key [N_CHANNELS];
volatile uint32_t synth_active [N_CHANNELS];
volatile uint32_t synth_state [N_CHANNELS];
volatile uint32_t synth_envl_add [N_CHANNELS];
volatile uint32_t synth_envl_sub [N_CHANNELS];
volatile uint32_t synth_envl_goal[N_CHANNELS];
volatile int_fast8_t synth_prev [N_CHANNELS];
volatile int_fast8_t synth_next [N_CHANNELS];
...
uint8_t CH_ACTIVE [N_NOTES];
int_fast8_t CH_INDEX [N_NOTES];
volatile uint32_t PITCH [N_NOTES];
volatile int8_t SAMPLE [N_SAMPLE] = DEFAULT_SAMPLE;
如你所见,数组的大小是一个定义在头文件中的常量:
#define N_NOTES 97 // = (9 - 1) * 12 + 1
#define N_CHANNELS 12 //EVEN NUMBER
#define N_SAMPLE 256
我希望这些数组有一个可以稍后覆盖的初始值。 对于其中之一,我可以这样做:
volatile int8_t SAMPLE [N_SAMPLE] = DEFAULT_SAMPLE;
因为我知道N_SAMPLE 将永远是 256。
所以我可以这样定义:
#define DEFAULT_SAMPLE \
{ \
0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, \
0x7D, 0x7C, 0x7B, 0x7A, 0x7A, 0x79, 0x78, 0x76, \
0x75, 0x74, 0x73, 0x71, 0x70, 0x6E, 0x6D, 0x6B, \
0x6A, 0x68, 0x66, 0x64, 0x62, 0x60, 0x5E, 0x5C, \
0x5A, 0x57, 0x55, 0x53, 0x50, 0x4E, 0x4B, 0x49, \
0x46, 0x44, 0x41, 0x3E, 0x3C, 0x39, 0x36, 0x33, \
0x30, 0x2D, 0x2A, 0x27, 0x25, 0x22, 0x1E, 0x1B, \
0x18, 0x15, 0x12, 0x0F, 0x0C, 0x09, 0x06, 0x03, \
0x00, 0xFC, 0xF9, 0xF6, 0xF3, 0xF0, 0xED, 0xEA, \
0xE7, 0xE4, 0xE1, 0xDD, 0xDA, 0xD8, 0xD5, 0xD2, \
0xCF, 0xCC, 0xC9, 0xC6, 0xC3, 0xC1, 0xBE, 0xBB, \
0xB9, 0xB6, 0xB4, 0xB1, 0xAF, 0xAC, 0xAA, 0xA8, \
0xA5, 0xA3, 0xA1, 0x9F, 0x9D, 0x9B, 0x99, 0x97, \
0x95, 0x94, 0x92, 0x91, 0x8F, 0x8E, 0x8C, 0x8B, \
0x8A, 0x89, 0x87, 0x86, 0x85, 0x85, 0x84, 0x83, \
0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, \
0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, \
0x82, 0x83, 0x84, 0x85, 0x85, 0x86, 0x87, 0x89, \
0x8A, 0x8B, 0x8C, 0x8E, 0x8F, 0x91, 0x92, 0x94, \
0x95, 0x97, 0x99, 0x9B, 0x9D, 0x9F, 0xA1, 0xA3, \
0xA5, 0xA8, 0xAA, 0xAC, 0xAF, 0xB1, 0xB4, 0xB6, \
0xB9, 0xBB, 0xBE, 0xC1, 0xC3, 0xC6, 0xC9, 0xCC, \
0xCF, 0xD2, 0xD5, 0xD8, 0xDA, 0xDD, 0xE1, 0xE4, \
0xE7, 0xEA, 0xED, 0xF0, 0xF3, 0xF6, 0xF9, 0xFC, \
0xFF, 0x03, 0x06, 0x09, 0x0C, 0x0F, 0x12, 0x15, \
0x18, 0x1B, 0x1E, 0x22, 0x25, 0x27, 0x2A, 0x2D, \
0x30, 0x33, 0x36, 0x39, 0x3C, 0x3E, 0x41, 0x44, \
0x46, 0x49, 0x4B, 0x4E, 0x50, 0x53, 0x55, 0x57, \
0x5A, 0x5C, 0x5E, 0x60, 0x62, 0x64, 0x66, 0x68, \
0x6A, 0x6B, 0x6D, 0x6E, 0x70, 0x71, 0x73, 0x74, \
0x75, 0x76, 0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, \
0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F \
}
对于其他数组,我不知道这一点。
例如,我想创建一个#define DEFAULT_SYNTH_NEXT,它将变为:{ 1, 2, 3, 4, 5, 6, 7, -1} 当N_CHANNELS 等于8,{ 1, 2, 3, 4, 5, -1} 当N_CHANNELS 等于6,
等等。
创建一个#define DEFAULT_CH_ACTIVE,它是一个用N_NOTES 值-1 填充的数组。
等等等等。
是否有可能使用 C 预处理器以上述方式实现依赖于先前定义的数字的 #define?
不知何故(递归?)(迭代?)产生预期的结果?
我找到了一篇文章http://jhnet.co.uk/articles/cpp_magic,但这看起来不太可读和可理解,我还没有设法弄清楚。 我希望能更清楚地阅读。
我看到了我想要的 2 个替代方案,但它们并不理想:
备选方案 1 静态定义如下:
#define DEFAULT_SYNTH_PREV {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
#define DEFAULT_SYNTH_NEXT {1, 2, 3, 4 ,5, 6, 7, 8, 9, 10, 11, -1}
等等,但是每次更新其中一个值时我都必须手动编辑它。
备选方案 2 是在进入主循环之前在 for() 循环中初始化 main() 函数中的数组。
这就是我目前正在做的,
set_tuning(DEFAULT_TUNING);
for(i=0; i<N_CHANNELS; ++i)
{
synth_counter[i] = 0;
synth_pitch[i] = 0;
synth_envelope[i] = 0;
synth_envl_add[i] = 0;
synth_envl_sub[i] = 0;
synth_envl_goal[i] = 0;
synth_active[i] = 0;
synth_state[i] = ENVL_0;
if (i==0)
synth_prev[i] = -1;
else
synth_prev[i] = i-1;
if (i==(N_CHANNELS - 1))
synth_next[i] = -1;
else
synth_next[i] = i+1;
synth_key[i] = -1;
}
for (i=0; i<N_NOTES; ++i)
{
CH_ACTIVE[i] = 0;
CH_INDEX[i] = -1;
}
这确实用所需的值预填充数组,但它不如通过从闪存复制到默认包含在项目中的启动代码中的重置处理程序中的 RAM 来预填充预定义变量的代码优化代码:
Reset_Handler:
ldr r0, =_estack
mov sp, r0 /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2]
adds r2, r2, #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
这就是为什么我仍然希望能够“动态地”#define 数组初始化器
【问题讨论】:
-
忘记预处理器。编写代码生成器。
-
#define N_NOTES 97 // = (9 - 1) * 12 + 1- 不要这样做。如果一个数字由于数学运算而有意义,请将数学运算放入数字定义中。我看到了一些错误,这些错误会带来不愉快的后果,比如出现这样的数学错误。 -
按要求回答问题 - 可能是可能的,但这将是一个看起来非常糟糕的代码。复杂的 PP 构造令人不快,是排除故障和产生神秘错误的噩梦。只是代码生成。
-
@Neil - 静态变量在超出范围时保留值。但这些都是全局变量,所以总是在范围内。全局,因为中断处理函数必须看到它们,它们代表设备的全局状态。预处理器宏只定义初始值。
-
@SergeyA "just codegen" - 我有点希望在这个项目中避免这种情况,因为它似乎不够复杂,但毕竟这可能是解决方案。
标签: c c-preprocessor