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)
我为什么要这样做?将不相关的信息隐藏在您的显示器之外。删除状态机中的许多选项卡。通过使用简单的语法来提高整体可读性。与第三个库函数一样,您需要知道如何使用代码,而不是知道函数是如何实现的。
您不需要知道状态如何表示它已准备就绪。知道所讨论的函数被用作状态函数比知道它返回一个位变量更重要。
我也在使用前测试宏。所以我不会向某人提供可能表现出奇怪行为的状态机。
这里没有必要使用宏,这样做会导致高度不惯用的 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)
(我根据您的示例猜测适当的参数名称;根据需要进行调整。)
更重要的是,它看起来好像ledT和ledPin总是配对并属于一起,在这种情况下,您应该考虑将它们放入struct:
struct led {
pin_t pin;
int interval;
};
void toggle_if_unset(struct led *led, int new_interval);
Run Code Online (Sandbox Code Playgroud)
或者类似的东西。