Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using open/close braces in macros to enforce pairing in C

Suppose that I have a requirement that if an operation is performed within a scope, then it must be undone in the same scope. An example of that is entering and leaving a critical section.

In order to enforce users to use paired do - undo operations, a pair of macros is defined that use open and close braces:

#define BEGIN \
{ \
    do_something();

#define END \
    undo_something(); \
}

Of course, there are ways that a "malicious" coder can trick those macros (e.g. by adding a an opening or closing brace), but generally this helps remembering that a BEGIN must be followed by an END. Moreover, if, for example, an existing BEGIN is commented out, the compiler will complain, indicating that the END must be removed also.

I have seen this is several internal projects. As I said, it does not offer 100% protection but could this practice prove harmful in any way? Is this a well-known practice?

like image 955
Kostas Avatar asked Jan 31 '17 08:01

Kostas


2 Answers

If I understand the question you want to enforce the use of BEGIN / END.

You can do that using the infamous 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);

Then, if BEGIN is used without the END part you receive an error:

error: label ‘check_label_end’ used but not defined

EDIT:

As pointed out by @ KlasLindbäck in comments, this version limits the use of BEGIN / END to once per function.

You can pass a label name in order to use several blocks:

#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)
like image 171
David Ranieri Avatar answered Sep 23 '22 04:09

David Ranieri


For simple cases I don't see a problem, but you can construct scenarious, where this breaks your code:

BEGIN
...
for(...) {
    END
    ...
    BEGIN
}
...
END
like image 41
MikeMB Avatar answered Sep 22 '22 04:09

MikeMB