假设我要求如果在范围内执行操作,则必须在同一范围内撤消操作。一个例子是进入和离开关键部分。
为了强制用户使用配对的do-undo操作,定义了一对使用open和close括号的宏:
#define BEGIN \
{ \
do_something();
#define END \
undo_something(); \
}
当然,有很多方法可以防止"恶意"编码器可以欺骗这些宏(例如通过添加一个开口或右大括号),但通常这有助于记住BEGIN
必须后跟END
。此外,例如,如果注释掉现有的BEGIN
,编译器将会抱怨,表明还必须删除END
。
我看到这是几个内部项目。正如我所说,它不提供100%的保护,但这种做法是否可以证明有害?这是一个众所周知的做法吗?
答案 0 :(得分:4)
如果我理解您要强制使用BEGIN
/ END
的问题。
你可以使用臭名昭着的goto
:
#define BEGIN \
do { \
goto check_label_end; \
label_begin: \
puts("begin"); \
} while (0);
#define END \
do { \
puts("end"); \
break; \
check_label_end: \
goto label_begin; \
} while (0);
然后,如果在没有BEGIN
部分的情况下使用END
,您会收到错误消息:
error: label ‘check_label_end’ used but not defined
修改强>
正如@KlasLindbäck在评论中指出的那样,此版本限制了每个功能使用BEGIN
/ END
一次。
您可以传递标签名称以使用多个块:
#define BEGIN(op) \
do { \
goto check_label_end_##op; \
label_begin_##op: \
puts("begin"); \
} while (0);
#define END(op) \
do { \
puts("end"); \
break; \
check_label_end_##op: \
goto label_begin_##op; \
} while (0);
BEGIN(undo)
...
END(undo)
BEGIN(something_else)
...
END(something_else)
答案 1 :(得分:2)
对于简单的情况,我没有看到问题,但是你可以构建一个有趣的地方,这会破坏你的代码:
BEGIN
...
for(...) {
END
...
BEGIN
}
...
END
答案 2 :(得分:2)
这样做的明智方法不是通过宏,而是通过功能。例如:
typedef void task_t (void);
inline void do_critical_stuff (task_t* task)
{
enter_critical_section();
task();
leave_critical_section();
}
或者,如果您正在寻找完全可变的东西:
inline void do_stuff (begin_t* begin, task_t* task, end_t* end)
{
begin();
task();
end();
}
答案 3 :(得分:0)
#define FOO(body) {\
do_something();\
body\
undo_something();\
}
您可以使用此宏:
FOO({
//your code here
})
-
编辑:
好的,StoryTeller的例子以我从未见过的方式轻松破解我的代码。
我想我很少在一行中写出多个声明。
逗号运算符和函数调用永远不会像a=(1,2);
或memcpy(&a,&b,1);
答案 4 :(得分:0)
我没有看到任何严重的问题,BEGIN
/ END
使用(和缩进)的方式与其他块相同。
显而易见的警告是,return
/ longjmp
/ goto
打破了这种模式,但只要所有程序员都知道这一点,就不应该成为一个问题。< / p>
示例:
void foo() {
...
BEGIN
...
if (some_condition) {
return; // Cleanup code skipped
}
...
END
...
}