我可以把这个要求变成一个宏吗?

bas*_*els 0 c macros 8051 keil

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

if(!ledT) { 
    ledT = 200;
    // code
    // code
    // code 
}
Run Code Online (Sandbox Code Playgroud)

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

if(!ledT) { ledT = 200;
    // code 
    // code 
    // code  
}
Run Code Online (Sandbox Code Playgroud)

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

expired(ledT, 200) {
    // code 
    // code 
    // code 
}
Run Code Online (Sandbox Code Playgroud)

我在我的状态机代码中使用类似的东西作为入口状态。

if(runOnce) { runOnce = false;
    // code 
    // code 
    // code 
Run Code Online (Sandbox Code Playgroud)

所需的语法:

entryState {
    // code 
    // code 
    // code 
Run Code Online (Sandbox Code Playgroud)

.

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

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

expired(ledT, 200); // expired is macro, not function
    // code
    // code
    // code
}
Run Code Online (Sandbox Code Playgroud)

所以这是不可能的。

在阅读宏的同时,我读到了一些关于使用的有趣内容: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
Run Code Online (Sandbox Code Playgroud)

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

编辑:我需要添加一个补充,因为似乎不是每个人都知道我想要什么,最后给出的答案甚至不是针对手头的具体问题。不知何故,切换 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

目前使用这些宏:

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

我想我应该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
Run Code Online (Sandbox Code Playgroud)

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

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

我什至想用宏来交换它:

extern bit weatherStates(void) {
        if(enabled) switch(state){
            default: case weatherStatesIDLE: return true;
Run Code Online (Sandbox Code Playgroud)

break;} }
    else if(!weatherStatesT) enabled = true;
    return false;}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Kon*_*lph 5

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

改用函数:

int toggle_if_unset(int time, int pin, int interval) {
    if (time == 0) {
        time = 200;
        TOG(pin);
    }
    return time;
}
Run Code Online (Sandbox Code Playgroud)
ledT = toggle_if_unset(ledT, ledPin, 200);
Run Code Online (Sandbox Code Playgroud)

(我根据您的示例猜测适当的参数名称;根据需要进行调整。)

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

struct led {
    pin_t pin;
    int interval;
};

void toggle_if_unset(struct led *led, int new_interval);
Run Code Online (Sandbox Code Playgroud)

或者类似的东西。

  • @basknippels事实上,你被限制在一个不合格的不完全C编译器应该已经在你的问题的前面和中心提到。目前您的问题被标记为 [tag:c]。我的答案是 C 的规范答案。你想要一些不同的东西。 (2认同)