c - 我可以把这个要求变成一个宏吗?
问题描述
我有递减软件计数器的 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 个库函数一样,您需要知道如何使用代码,而不是知道函数如何发挥作用。
你不需要知道,一个状态如何表示它已经准备好了。知道所讨论的函数被用作状态函数比知道它返回一个位变量更重要。
我也在使用前测试宏。所以我不向某人提供可能表现出奇怪行为的状态机。
解决方案
这里没有必要使用宏,这样做会导致高度不习惯的 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);
或类似的东西。
推荐阅读
- python - 服务 'web' 构建失败,协议错误
- c# - 使用 Directory.GetFiles() 获取所有文件,这会获取一个文件但在我的文件夹中不存在
- ajax - 如何在 Spring MVC 中返回一个空的 JSON?
- ruby-on-rails - 无法在 Rails 6 usgin ActiveStorage 中将头像附加到模型
- spring - http.authorizeRequests().antMatchers("/").permitAll() 不起作用
- html - 将内联块 DIV 定位在 DIV 容器内(没有 flexbox)
- javascript - React 如何设置组件 id 以便能够使用 document.getElementById()
- javascript - 如何通过 on change 事件引用和更改单行 TD 元素
- react-native - Jest with Enzyme - 连接组件的快照看起来与我的代码不同
- python - Python - Pandas - 导入 Excel 文件,遍历每一行,添加新值,并添加到数据框