C macros with opening and closing tags?
-
01-07-2021 - |
题
I just started reading this article about exception handling in c with the use of setjmp( jmp_buf ) and longjmp( jmp_buf, int ). So I basically build the linked list that uses the local variables from type xRecord and links it to the list. (Example 2) It works just fine. But in example 3 the steps get summarized into macros (XTRY and XEND). What irritates me most is that the actual switch statement of example 2 just "vanished" in 3.
Example 2:
#define DIVIDE_BY_ZERO -3
int SomeFunction(int a, int b)
{
if (b == 0) // can't divide by 0
XRaise(DIVIDE_BY_ZERO);
return a / b;
}
void main(void)
{
XRecord XData;
XLinkExceptionRecord(&XData);
switch (setjmp(XData.Context))
{
case 0: // this is the code block
{
int Result = SomeFunction(7, 0);
// continue working with Result
}
break;
case DIVIDE_BY_ZERO:
printf("a division by zero occurred\n");
break;
default:
printf("some other error occurred\n");
break;
case XFINALLY:
printf("cleaning up\n");
}
XUnLinkExceptionRecord(&XData);
}
Example 3:
void main(void)
{
XTRY
case XCODE: // this is the code block
{
int Result = SomeFunction(7, 0);
// continue working with Result
}
break;
case DIVIDE_BY_ZERO: // handler for a
specific exception
printf("a division by zero occurred\n");
break;
default: // default handler
printf("some other error occurred\n");
break;
case XFINALLY: // finally handler
printf("cleaning up\n");
XEND
}
My question is, how can I build these "opening and closing" macros?
解决方案
If you compare the two examples, and keep in mind that C macros are simple text substitutions, what the macros should be is evident:
#define XTRY XRecord XData; \
XLinkExceptionRecord(&XData); \
switch (setjmp(XData.Context)) \
{
#define XEND } \
XUnLinkExceptionRecord(&XData);
Note the use of \
to allow the macro to span more than one line.
You may also want to have the macros open and close a new scope (by adding {
and }
), so that using the macros multiple in succession doesn't give an error due to multiple definitions of the variable XData
. You can also use the do / while(0)
trick to allow these macros to be placed directly inside if
, for
, etc. without issues.
其他提示
Don't hide the {}
this only causes trouble. With a C99 compliant compiler, you can hide local variables and some code that is executed before and after the block:
#define MY_BLOCK \
for (int once = 0; once < 1; ++once) \
for (XRecord XData = { 0 }; once < 1; ++once) \
for (XLinkExceptionRecord(&XData); (XUnLinkExceptionRecord(&XData), (once < 1)); ++once) \
switch (setjmp(XData.Context))
Benefit would be that you only need one macro instead of two, and the {}
would clearly indicate the scope of the construct, even for your favorite editor.