首页 > 解决方案 > 我可以把这个要求变成一个宏吗?

问题描述

我有递减软件计数器的 C 程序。例如,如果我想每 2 秒闪烁一次 LED,我可以这样做:

if(!ledT) { 
    ledT = 200;
    // code
    // code
    // code 
}

因为我总是对每个计数器进行完全相同的组合,所以我倾向于输入一行。

if(!ledT) { ledT = 200;
    // code 
    // code 
    // code  
}

对于整个 if 行,我想改用宏。所以代码看起来像:

expired(ledT, 200) {
    // code 
    // code 
    // code 
}

我在状态机代码中使用类似的东西来表示进入状态。

if(runOnce) { runOnce = false;
    // code 
    // code 
    // code 

所需的语法:

entryState {
    // code 
    // code 
    // code 

.

#define entryState if(runOnce) { runOnce = false; // this ofcourse cannot work But something like this is what I want.

我已经做了几次尝试,但我一无所获。问题是{位于宏中间的某个地方,我想{在宏后面输入 a 因为众所周知,没有代码编辑器可以处理不相等数量的{and }

expired(ledT, 200); // expired is macro, not function
    // code
    // code
    // code
}

所以这是不可能的。

在阅读宏时,我读到了一些关于使用的有趣内容:do ... while(0)。这个“技巧”滥用编译器的优化功能来创建某个宏,否则这是不可能的。

本站

阐明了这种方式。

有没有办法使用某种“宏观技巧”来实现我想要的?

再一次,这正在转变:

// this
if(runOnce) {
    runOnce = false;
    // code
    // code
    // code

// into this
entryState {
    // code
    // code
    // code

// and this:
if(!someTimer) {
    someTimer = someInterval;
    // code
    // code
    // code

// must be transformed into:
timeExpired(someTimer, someInterval) {
    // code
    // code
    // code

并且也将接受诸如“不,根本无法完成”之类的答案(前提是您知道自己在说什么)

编辑:我需要添加一个补充,因为似乎不是每个人都知道我想要什么,最后给出的答案甚至不是针对手头的具体问题。不知何故切换 IO 突然变得很重要?因此,我更改了代码示例以更好地说明问题所在。

EDIT2:我同意 timeExpired 宏根本不会提高可读性

为了展示一些宏可以提高可读性,我将给出一个状态和状态机的片段。这就是我的代码中生成的状态的样子:

State(stateName) {
    entryState {
        // one time only stuff
    }
    onState {
        // continous stuff
        exitFlag = true; // setting this, exits the state
    }
    exitState {
        // one time only stuff upon exit
        return true;
    }
}

目前使用这些宏:

#define State(x) static bool x##F(void)
#define entryState if(runOnce) 
#define onState runOnce = false;
#define exitState if(!exitFlag) return false; else

我想我应该return true;在美国交换EXIT或换一些更漂亮的东西。调用这些状态的状态机看起来像:

#undef State

#define State(x) break; case x: if(x##F())
extern bit weatherStates(void) {
    if(enabled) switch(state){
        default: case weatherStatesIDLE: return true;

        State(morning) {
            if(random(0,1)) nextState(afternoon, 0);
            else            nextState(rain, 0); }

        State(afternoon) {
            nextState(evening, 0); }

        State(evening) {
            if(random(0,1)) nextState(night, 0);
            else            nextState(thunder, 0); }

        State(night) {
            nextState(morning, 0); }

        State(rain) {
            nextState(evening, 0); }

        State(thunder) {
            nextState(morning, 0); }

        break; }
    else if(!weatherStatesT) enabled = true; 
    return false; }
#undef State

唯一没有生成的是“nextState()”函数之前的“if”和“else”。这些“流动条件”需要填写。

如果为用户提供了一个小例子或一个解释,他在填写状态时应该没有任何困难。他还应该能够手动添加状态。

我什至想用宏来交换这个:

extern bit weatherStates(void) {
        if(enabled) switch(state){
            default: case weatherStatesIDLE: return true;

break;} }
    else if(!weatherStatesT) enabled = true;
    return false;}

我为什么要这样做?将不相关的信息隐藏在您的显示器之外。删除状态机中的许多选项卡。通过使用简单的语法来提高整体可读性。与第 3 个库函数一样,您需要知道如何使用代码,而不是知道函数如何发挥作用。

你不需要知道,一个状态如何表示它已经准备好了。知道所讨论的函数被用作状态函数比知道它返回一个位变量更重要。

我也在使用前测试宏。所以我不向某人提供可能表现出奇怪行为的状态机。

标签: cmacroskeil8051

解决方案


这里没有必要使用宏,这样做会导致高度不习惯的 C 代码与正确的 C 代码相比没有任何优势。

改用函数:

int toggle_if_unset(int time, int pin, int interval) {
    if (time == 0) {
        time = 200;
        TOG(pin);
    }
    return time;
}
ledT = toggle_if_unset(ledT, ledPin, 200);

(我根据您的示例猜测适当的参数名称;酌情调整。)

更重要的是,它看起来好像ledT并且ledPin总是配对并且属于一起,在这种情况下,您应该考虑将它们放入struct

struct led {
    pin_t pin;
    int interval;
};

void toggle_if_unset(struct led *led, int new_interval);

或类似的东西。


推荐阅读