使用宏进行配置

发布于 2024-07-14 04:15:12 字数 670 浏览 12 评论 0原文

我正在用 C 语言为嵌入式处理器编写固件。 我想将所有配置信息放在一个名为 config.h 的头文件中。 这会导致 ADC 初始化出现问题,简单的#defines 无法解决问题。 现在代码如下:

config.h

#define NUMBER_OF_POTS  1
#define POT_1_CHANNEL  27

adc.c

#define MAKE_CSS(channel) _CSS##channel
#define CALL_MAKE_CSS(channel) MAKE_CSS(channel)

void initialize_adc() {
   CALL_MAKE_CSS(POT_1_CHANNEL);
}

如果我将 config.h 更改为:

#define NUMBER_OF_POTS  2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

adc.c 应该自动添加第二个 CALL_MAKE_CSS 带有一些宏技巧。

我想问题是:是否有一个技巧可以为您提供宏的 for 循环功能?

谢谢,

史蒂夫。

I'm writing firmware in C for an embedded processor. I want to have all the configuration information in one header file called config.h. This is causing problems with the ADC initialization, where simple #defines won't do the trick. Right now the code is like so:

config.h

#define NUMBER_OF_POTS  1
#define POT_1_CHANNEL  27

adc.c

#define MAKE_CSS(channel) _CSS##channel
#define CALL_MAKE_CSS(channel) MAKE_CSS(channel)

void initialize_adc() {
   CALL_MAKE_CSS(POT_1_CHANNEL);
}

What I want to do is not have to touch adc.c if I change config.h to:

#define NUMBER_OF_POTS  2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

adc.c should just automatically add a second CALL_MAKE_CSS with some macro trickery.

I guess the question is: is there a trick that gives you for loop capability with a macro?

Thanks,

Steve.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

对你而言 2024-07-21 04:15:12

我没有测试这个:

// config.h

#define NUMBER_OF_POTS  2
extern int pots[];

// config.c

int pots[NUMBER_OF_POTS] = {
    27,
    29
};


// adc.c

void initialize_adc() {
    for (int i = 0; i < NUMBER_OF_POTS; i++) {
        CALL_MAKE_CSS(pots[i]);
    }
}

I didn't test this:

// config.h

#define NUMBER_OF_POTS  2
extern int pots[];

// config.c

int pots[NUMBER_OF_POTS] = {
    27,
    29
};


// adc.c

void initialize_adc() {
    for (int i = 0; i < NUMBER_OF_POTS; i++) {
        CALL_MAKE_CSS(pots[i]);
    }
}
×纯※雪 2024-07-21 04:15:12

您不必完全依赖宏。 只需将您的“幻数”定义为#defines。

例如:

在 config.h 中:

#define NUMBER_OF_POTS 2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

unsigned int PotChannelList[NUMBER_OF_POTS] = {POT_1_CHANNEL, POT_2_CHANNEL};

在 adc.c 中:

for(i = 0; i < NUMBER_OF_CHANNELS; i++)
{
  initialize_adc(PotChannelList[i]);
}

您仍然在 config.h 中定义设置,并且在添加通道时不必更改 adc.c。 您只需将其添加到列表中即可。 列表顺序还定义了初始化的顺序。

编辑:抱歉格式混乱......

You don't have to rely entirely on macros. Just define your 'magic numbers' as #defines.

For example:

In config.h:

#define NUMBER_OF_POTS 2
#define POT_1_CHANNEL  27
#define POT_2_CHANNEL  29

unsigned int PotChannelList[NUMBER_OF_POTS] = {POT_1_CHANNEL, POT_2_CHANNEL};

In adc.c:

for(i = 0; i < NUMBER_OF_CHANNELS; i++)
{
  initialize_adc(PotChannelList[i]);
}

You still define the setup in config.h and don't have to change adc.c when you add a channel. You just add it to the list. The list order also defines the order of initialization.

EDIT: Sorry about the formatting mess...

不…忘初心 2024-07-21 04:15:12

看看 boost.preprocessor。 尽管 boost 通常适用于 C++,但预处理器元编程库仅适用于 CPP,因此它可能会执行您想要的操作。 它提供了一些数据结构(列表、元组)和迭代宏。

抱歉,我无法给你任何例子,如果它真的能达到你想要的效果,或者至少提供另一种方式,因为我很少需要它,而且已经是很久以前的事了。

注意刚刚看到施罗德的回答。 如果没有必要的话,不依赖PP仍然是最好的选择......

Have a look at boost.preprocessor. Although boost is usually for C++, the preprocessor metaprogramming lib works, well, just with the CPP, so it may do what you want. It provides a few datastructures (lists, tuples) and iteration macros.

Sorry, I can't give you any example if it really does what you want, or at least provides another way, because I seldom needed it, and it's too long ago.

Note Just saw Schroeder's answer. Not relying on the PP if it is not necessary is still the best option...

梦幻的味道 2024-07-21 04:15:12

C 预处理器不能执行循环。 您要么必须在 C 代码中执行循环,要么如果您确实需要在编译时执行类似循环的操作,您可以编写自己的预处理器(可以是一个简单的 shell 脚本) ,例如)生成必要的代码。

The C preprocessor cannot do loops. You'll either have to do the looping in C code, or if you really need to do something loop-like at compile time, you can write your own preprocessor (which can just be a simple shell script, e.g.) that generates the necessary code.

难如初 2024-07-21 04:15:12

尽管您无法使用预处理器执行循环,但您可以执行展开循环。 因此,如果您知道您永远不会拥有超过 4 个底池,您可以这样做;

void initialize_adc() {
  #if NUMBER_OF_POTS > 0
    CALL_MAKE_CSS(POT_1_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 1
    CALL_MAKE_CSS(POT_2_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 2
    CALL_MAKE_CSS(POT_3_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 3
    CALL_MAKE_CSS(POT_4_CHANNEL);
  #endif
}

与其他解决方案相比,这样做的唯一好处是根本没有运行时开销。 当且仅当添加另一个通道时,正如提问者想要的那样,额外的内联代码“神奇地”出现。 要从函数调用中提取丑陋的内容(代价是将其放在代码的前面),请定义 4 个新宏,每个宏使用相同的 #if NUMBER_OF_POTS > x 技术。 然后你就可以简单地走了;

void initialize_adc() {
  INIT_CSS_1();
  INIT_CSS_2();
  INIT_CSS_3();
  INIT_CSS_4();
}

Although you can't do loops with the preprocessor, you can do unrolled loops. So if you know you're never going to have more than 4 pots you could do this;

void initialize_adc() {
  #if NUMBER_OF_POTS > 0
    CALL_MAKE_CSS(POT_1_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 1
    CALL_MAKE_CSS(POT_2_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 2
    CALL_MAKE_CSS(POT_3_CHANNEL);
  #endif
  #if NUMBER_OF_POTS > 3
    CALL_MAKE_CSS(POT_4_CHANNEL);
  #endif
}

The only benefit of this compared to other solutions here is that there is no runtime overhead at all. Extra inline code "magically" appears if and only if another channel is added, just as the questioner wanted. To extract the ugliness from within the function call (at the cost of putting it earlier in your code instead), define 4 new macros each using the same #if NUMBER_OF_POTS > x technique. Then you'd be able to go simply;

void initialize_adc() {
  INIT_CSS_1();
  INIT_CSS_2();
  INIT_CSS_3();
  INIT_CSS_4();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文