portability and safety of C macro using lambda parameter - c

Preface
I know that there are several libraries for auto-testing available.
Let's ignore that for this question, please.
Motivation
Implementing some library I got tired of manual testing, so I started to write a "self-test" program, starting with code using many assert()s.
Unfortunately when an assert() fails, only limited information is shown on the screen, and I would typically have to use the debugger to examine the core dump to get more details of the failure.
So I added a macro that allows a printf()-like output (implemented via the E() (for error) macro) when an assertion fails; I named that macro VA() (for verbose assertion):
#define VA(assert_cond, msg, ...) do { \
if ( !(assert_cond) ) E(msg, ##__VA_ARGS__); \
assert(assert_cond); \
} while (0)
Using that would look like this:
VA(FASTWORD(FASTWORD_BITS - 1) == 0, "%s: FASTWORD() failed", __func__);
As the self-test program used array-like data structures, I needed to inspact those as well, so I output those before doing the tests, resulting in a lot of output even when all tests succeed.
So I invented another macro, VFA() (verbose failed assertion) that uses a "lambda parameter" like this:
#define VFA(assert_cond, cmd, msg, ...) do { \
if ( !(assert_cond) ) { \
E(msg, ##__VA_ARGS__); \
cmd; \
} \
assert(assert_cond); \
} while (0)
While writing that I wondered how the preprocessor would parse commata for a use case like this:
VFA(fw[0] == out_fw0 && fw[1] == out_fw1,
dump_fastwords_range(fw, 4, pos, (pos + count) % FASTWORD_BITS),
"%s: __clear_fw_bits_up(%d, %d) failed", context, pos, count);
I mean it could be possible that the condition could be the first parameter, dump_fastwords_range(fw could be the second, 4 could be the third, and so on...
However that is not the case with gcc at least.
The other thing is cmd; in the macro:
My first version did not include the semicolon, so I would have to write (which looks really ugly):
VFA(fw[0] == out_fw0 && fw[1] == out_fw1,
dump_fastwords_range(fw, 4, pos, (pos + count) % FASTWORD_BITS);,
"%s: __clear_fw_bits_up(%d, %d) failed", context, pos, count);
OK, here's another use example of my macro:
VFA(fw[0] == out_fw0 && fw[1] == out_fw1,
{
const unsigned first = pos >= count ?
pos - count : FASTWORD_BITS + pos - count + 1;
dump_fastwords_range(fw, 4, first, pos);
},
"%s: __clear_fw_bits_dn(%d, %d) failed", context, pos, count);
Questions
The questions I have are:
Is parsing of the macro parameters portable across compilers?
Will the cmd use create any trouble, considering the parameter could be rather complex (as the last example suggests)?

Is parsing of the macro parameters portable across compilers?
No. ##__VA_ARGS__ is a non-portable gcc extension. What does ##__VA_ARGS__ mean?
Will the cmd use create any trouble, considering the parameter could be rather complex (as the last example suggests)?
Items within () of that macro parameter will mean that it all gets treated like a single pre-processor token and expanded as such. You can peek at the pre-processor output if you are curious. Formally this is specified in C17 6.10.3/10:
Each subsequent instance of the
function-like macro name followed by a ( as the next preprocessing token introduces the
sequence of preprocessing tokens that is replaced by the replacement list in the definition
(an invocation of the macro). The replaced sequence of preprocessing tokens is
terminated by the matching ) preprocessing token, skipping intervening matched pairs of left and right parenthesis preprocessing tokens.
So it shouldn't create any trouble unless you do truly evil stuff like using goto or setjmp etc from inside it.

Related

How to implement Go's defer() in C so that it allows declaring vars?

In this Modern C video there's a trick that allows to postpone execution of a code until the block/scope exits. It's used as follows:
int main()
{
int foo=0, bar;
const char *etc = "Some code before defer";
defer(profile_begin(), profile_end())
{
/* Some code, which will be automatically
* preceded by call to profile_begin() and
* followed by run of profile_end().*/
foo++;
bar = 1;
}
etc = "Some code after defer";
foo = bar + 1;
}
Implementation from the video:
#define macro_var_line(name) concat(name, __LINE__)
#define defer(start,end) for( \
int macro_var_line(done) = (start,0); \
!macro_var_line(done); \
(macro_var_line(done) += 1), end)
It's pretty simply implemented. What might be confusing is the macro_var_line(name) macro. Its purpose is to simply ensure that a temporary variable will have a unique, "obfuscated" name by adding current line number to it (of where defer is called).
However the problem is that one cannot pass code to start snippet that declares new variables, because it is pasted in the for() comma operator that uses int type (the int macro_var_line(done) = …). So it's not possible to, eg.:
defer(FILE *f = fopen("log.txt","a+"), fclose(f))
{
fprintf(f,"Some message, f=%p",f);
}
I would want to have such macro, capable of declaring new vars in start snippet. Is it achievable with standard C99, C11 or maybe some GCC extensions?
UPDATE: I've found a solution utilizing GCC nested functions. Basically, the { bblock } that's following the defer() macro becomes nested function body. And it's possible to forward declare the nested function and invoke it from before the block, i.e.:
#define defer(start,end) \
auto void var_line(routine) (void); \
start; \
/* Invoke above predeclared void routine_123(void) function */ \
var_line(routine)(); \
end; \
/* Define the nested function */ \
void var_line(routine) (void)
UPDATE2: Here's an elegant version which:
runs first leading statements as start and the last one as the end code,
runs the very first statement in its own for()/declarative space,
runs the block properly via an if(cond == 0) check/block start up.
#define defer(...) \
for (int var_line(cond) = 0; var_line(cond) == 0; ) \
for (FIRST_ARG(__VA_ARGS__); var_line(cond) == 0; ) \
for (SKIP_LAST_ARG(SKIP_FIRST_ARG(__VA_ARGS__)); \
var_line(cond) == 0; \
var_line(cond) += 1 ) \
for (int var_line(cond_int) = 0; \
var_line(cond_int) <= 1; \
var_line(cond_int) += 1 ) \
if (var_line(cond_int) == 1) \
{ \
LAST_ARG(__VA_ARGS__); \
} else if (var_line(cond_int) == 0)
As I expressed in comments, my recommendation is to avoid using such a thing in the first place. Whatever your video might have said or implied, the prevailing opinion among modern C programmers is that macro usage should be minimized. Variable-like macros should generally represent context-independent constant values, and function-like macros are usually better implemented as actual functions. That's not to say that all macro use must be avoided, but most modern C professionals look poorly on complex macros, and your defer() is complex enough to qualify.
Additionally, you do yourself no favors by trying to import the style and idioms of other languages into C. The common idioms of each language become established because they work well for that language, not, generally, because they have inherent intrinsic value. I advise you to learn C and the idioms that C programmers use, as opposed to how to write C code that looks like Go.
With that said, let's consider your defer() macro. You write,
However the problem is that one cannot pass code to start snippet that declares new variables
, but in fact the restriction is stronger than that. Because the macro uses the start argument in a comma expression (start,0), it needs to be an expression itself. Declarations or complete statements of any kind are not allowed. That's only indirectly related to that expression appearing in the first clause of a for statement's control block. (The same applies to the end argument, too.)
It may also be important to note that the macro expands to code that fails evaluate the end expression if execution of the associated statement terminates by branching out of the block via a return or goto statement, or by executing a function that does not return, such as exit() or longjmp(). Additionally, unlike with Go's defer, the end expression is evaluated in full after the provided statement -- no part of it is evaluated before, which might surprise a Go programmer. These are characteristics of the options presented below, too.
If you want to pass only the start and end as macro arguments, and you want to allow declarations to appear in start, then you could do this:
// Option 1
#define defer(start,end) start; for( \
int macro_var_line(done) = 0; \
!done; \
(macro_var_line(done) += 1), (end))
That moves start out of the for statement in the macro's replacement text, to a position where arbitrary C code may appear. Do note, however, that any variable declarations will then be scoped to the innermost containing block.
If you want to limit the scope of your declarations then there is also this alternative and variations on it, which I find much more straightforward than the original:
// Option 2
#define defer(start, end, body) { start; body end; }
You would use that like so:
defer(FILE *f = fopen("log.txt","a+"), fclose(f), // argument list continues ...
fprintf(f,"Some message, f=%p",f);
);
That is somewhat tuned to your particular example, in that it assumes that the body is given as a sequence of zero or more complete statements (which can include blocks, flow-control statements, etc). As you can see, it also requires the body to be passed as a macro argument instead of appearing after the macro invocation, but I consider that an advantage, because it facilitates recognizing the point where the deferred code kicks in.
You can simulate defer by using the __attribute__((cleanup(...))) feature of GCC and Clang. Also see this SO question about freeing a variable.
For instance:
// the following are some utility functions and macros
#define defer(fn) __attribute__((cleanup(fn)))
void cleanup_free(void* p) {
free(*((void**) p));
}
#define defer_free defer(cleanup_free)
void cleanup_file(FILE** fp) {
if (*fp == NULL) { return; }
fclose(*fp);
}
#define defer_file defer(cleanup_file)
// here's our code:
void foo(void) {
// here's some memory allocation
defer_free int* arr = malloc(sizeof(int) * 10);
if (arr == NULL) { return; }
// some file opening
defer_file FILE* fp1 = fopen("file1.txt", "rb");
if (fp1 == NULL) { return; }
// other file opening
defer_file FILE* fp2 = fopen("file2.txt", "rb");
if (fp2 == NULL) { return; }
// rest of the code
}
There is actually an effort in the standard's committee to standardize a defer feature. The paper proposal also comes with a reference implementation. The idea is to propose such a feature that may be implemented with the least compiler magic possible.
If all goes to plan, that feature could even be rebase on lambdas, if we get these into C23 in time.
You could use a trick from "Smart Template Container for C". See link.
#define c_autovar(declvar, ...) for (declvar, *_c_ii = NULL; !_c_ii; ++_c_ii, __VA_ARGS__)
Basically you declare a variable and hijack it's type to form a NULL pointer. This pointer is used as a guard to ensure that the loop is executed only once.
Incrementing NULL pointer is likely Undefined Behavior because the standard only allows to form a pointer pointing just after an object and NULL points to no object. However, it's likely run everywhere.
I guess you could get rid of UB by adding a global variable:
int defer_guard;
And setting the guard pointer to a pointer to defer_guard in the increment statement.
extern int defer_guard;
#define defer_var(declvar, cleanup) \
for (declvar, *_c_ii = NULL; \
!_c_ii; \
_c_ii = (void*)&defer_guard, cleanup)
It will work fine when invoked as:
defer_var(FILE *f = fopen("log.txt","a+"), fclose(f))
{
fprintf(f,"Some message, f=%p",f);
}
EDIT
Actually it is possible to derive a macro that will accept both expression and declaration as start. One must use two for loops instead of one.
#define DEFER(start, end) \
for (int _done = 0; !_done;) \
for (start; !(_done++); end)
int main() {
DEFER(FILE *f = fopen("log.txt","a+"), fclose(f)) {
fprintf(f,"Some message, f=%p", (void*)f);
}
FILE *f;
DEFER(f = fopen("log.txt","a+"), fclose(f)) {
fprintf(f,"Some message, f=%p", (void*)f);
}
return 0;
}

Macro that resolves to first N characters of argument

I am working on a heavily resource-constrained embedded platform.
I want a macro that will capture function call errors and log them to a fixed-size buffer.
My wish is to be able to do something like
returnType retval;
CAPTURE_ERRORS(retval, function_name, argument1, moreArgsMaybe);
if (retval) { other_error_handling(); }
Where
#define N 12
#define CAPTURE_ERRORS(retval, func, ...) \
do { retval = func(__VA_ARGS__); \
if (retval!=0) write_log_entry(#func[0:N],(int)retval); \
} while (0)
Obviously, the Python slice syntax won't work. Is there any way to get the first N characters of a stringized macro argument?
(I don't want to do the truncation inside write_log_entry, because then the whole long function name will be stored in the executable image, only to be thrown away later.)
I am not aware of any way as a string. (Somebody who is aware, please enlighten me!)
Edit The easiest way I know is to make all your function names no more than N characters long! Think of all that Fortran code with N=6. :)
The second easiest way I know is to pass an additional parameter to CAPTURE_ERRORS:
#define N 12
/* vvvv */
#define CAPTURE_ERRORS(retval, func, tag, ...) \
do { retval = func(__VA_ARGS__); \
if (!retval) write_log_entry(#tag,(int)retval); \
} while (0) /* ^^^^ */
and
CAPTURE_ERRORS(retval, function_name, function_nam, argument1, moreArgsMaybe);
^^^^^^^^^^^^
This is a sufficiently restricted form that you could automatically stuff tag in your existing CAPTURE_ERRORS call with a Python (or even sed!) script that you run before compiling.
Edit
A discussion thread coming to the same conclusion — use an external tool.
In C++, you could likely do this at compile time with a template. :) Not unlike this question, but stopping at length N.

getting the variable values in #define definition

Here is what I am trying to do.
step1) I want to call a macro with a conditional statement(simple are compounded) like
for eg:
MACRO1(a==1)
MACRO1((i!=NULL) && (j>10))
step2) Here is how i am defining this macro
#define MACRO1(condition) \
if(!(condition)) ??????????????????????????
Here in the definition of the macro, if the condition statement fails. I want to print the variable values so that I will be useful to know the exact reason.
I used #condition in the definition, but it just printing the condition, instead of the values of the variables used in the condition. Please help.
You could do something along these lines:
#define MACRO1(condition, msg) \
if(!(condition)) { printf msg; }
and use it as follows:
MACRO1(a==1, ("a: %d\n", a))
MACRO1((i != NULL) && (j>10), ("i: %p, j: %d\n", i, j));
The C preprocessor is just a simple substitution engine, without the capability of analyzing the contents of expressions.
You shouldn't define macros that look like a function, but behave differently, in particular in your case may change control flow: an else that follows a macro that contains an if can apply to something different than the programmer (yourself after a week) thinks. Protect the if such that a dangling else will not apply to it
#define MACRO1(COND, ...) \
do { \
if (!(COND)) printf(stderr, "condition " #COND ": " __VA_ARGS_); \
} while (0)
This macro should always be called with a format string as second argument and the names of the variables that you want to see
MACRO1((toto != 78.0), "toto=%9\n", toto);
this should print you something like
condition (toto != 78.0): toto=3.14
There is no way that I know of to separate the variables from the condition.
However, you can pass them in as extra parameters:
#define MACRO(condition, printsyntax, ...) \
if(!(condition)) {\
printf("condition %s not met! (" printsyntax ")\n", #condition, __VA_ARGS__); \
};
You would use it as:
MACRO((i!=NULL) && (j>10), "i=%p, j=%d", i, j)
with an example result being:
condition (i!=NULL) && (j>10) not met! (i=(nil), j=11)
The compiler will splice together the constant strings into one string for the printf,
the condition will automatically be printed and the rest of the arguments are your job to get right.
Edit
After Jens' remark about the else I modified the code a bit to not allow for such structures without using do{}while();.

Variable no of argument in C Macro

I am writing some hardware specific code, where I want to use C Macros, the macro definition would be something like this:-
#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1) if(a[MODE][RESOURCE1] != x1) || \
(a[MODE][RESOURCE1] != y1)) \
a[MODE][RESOURCE1]=x3;
Since sometimes I can have more then 1 resource to allocate, such as:-
#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) if(a[MODE][RESOURCE1] != x1) || \
(a[MODE][RESOURCE1] != y1)) \
a[MODE][RESOURCE1]=x3;
if(a[MODE][RESOURCE2] != x1) || \
(a[MODE][RESOURCE2] != y1)) \
a[MODE][RESOURCE2]=x3;
Is there any way I can write a macro, which covers both cases, as it takes variable number of arguments?
I have used variable number of arguments, in macro for printf macros, but then how I will address those arguments, by their respective name, for example, if I modify the MACRO definition such as:0-
#define VALIDA_RESOURCE_AND_ALLOCATE(MODE,.....)
How will I identify RESOURCE1, RESOURCE2?
Your macros have a lot of repeated code in them. Simplifying them helps make a solution more apparent:
#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) do {\
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE1); \
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE2); \
} while(0)
Here, it's clearer that this is simply a repeated invocation of the first macro while iterating through a list of arguments.
Assuming you know that the data types being used here will always be consistent, you can try something like this (untested and written off of the top of my head):
#ifdef HARDWARE_PLATFORM_A
static sometype args[] = {
RESOURCE1,
RESOURCE2,
/* ... etc, etc */
};
#elif defined HARDWARE_PLATFORM_B
static sometype args[] = {
RESOURCE10,
RESOURCE11,
/* ... etc, etc */
};
/* repeat for all hardware platforms */
#endif
void initialization_function (void) {
int i;
for (i = 0; i < (sizeof(args) / sizeof(args[0])); ++i) {
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, args[i]);
}
}
where sometype is the data type of the arguments that you will be using for RESOURCE1, RESOURCE2, etc.
Given the complexity of what you are trying to do, you'd be a lot better off writing a function to do the iteration instead of a macro. You can still use a macro to create the RESOURCE list, but don't try to get the pre-processor to do the iteration for you. If you need to avoid the overhead of a function call (since you tagged this as 'embedded'), you can declare the functions inline and the result should be as efficient as using a macro. In the process, though, you'll gain things like type safety.
While it might be technically possible to do this with a macro, it would be a nasty hack that would most likely bring more problems than benefits. Doing complex procedural tasks with the pre-processor rarely turns out well.
The other alternative that you have is to use a code generator that takes a list of RESOURCE arguments from a file and generates a .c file containing the initialization code. The code generator would be written in a language much more powerful than the C pre-processor (almost any scripting language could be used here). This probably wouldn't be worth the trouble unless you had a long list of RESOURCEs, though.
One way you could accomplish it is don't pass in a variable number of arguments, but stick with two and make the second one be a list that can be used in an initialization. For example (trailing backslashes left off for clarity):
#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE, LIST)
{
int resources[] = LIST;
int count;
for(count = 0; count < sizeof(resources)/sizeof(int); count++) {
/* do stuff here for each resources[count] */
}
}
And then you can simply call it as such:
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, { RESOURCE1, RESOURCE2 } )
Note: there is more than one way to skin this cat, so pick your favorite answer and go with it :-)
Would this be too silly? ;-)
#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1,RESOURCE2) \
if(a[MODE][RESOURCE1] != x1) || (a[MODE][RESOURCE1] != y1)) \
a[MODE][RESOURCE1]=x3; \
if((RESOURCE1 != RESOURCE2) && (a[MODE][RESOURCE2] != x1) || (a[MODE][RESOURCE2] != y1))) \
a[MODE][RESOURCE2]=x3;
and Call it as below for single resource
VALIDATE_RESOURCE_AND_ALLOCATE(M1,R1,R1)
and like below for two?
VALIDATE_RESOURCE_AND_ALLOCATE(M1,R1,R2)

Creating function-like macros

gcc 4.4.2 c89
I have this code snippet that I have to repeat in a lot of my code. I am just wondering is there a way to make it short by using a macro function?
There is the code I would like to change.
ERR_INFO error_info; /* create error object */
ErrorInfo(&error_info); /* pass the address for it to be filled with error info */
fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); /* display the error msg */
And my attempt to create a macro function to use it.
#define DISPLAY_ERR(error_info) ErrorInfo(&error_info) error_info.msg
fprintf(stderr, "And the error is? [ %s ]\n", DISPLAY_ERR); /* display the error
Any suggestions would be most helpful,
If you really want a macro:
#define DISPLAY_ERR(error_info) \
do \
{ \
ErrorInfo(&(error_info)); \
fprintf(stderr, "And the error is? [ %s ]\n", (error_info).msg); \
} while(0)
You need the do... while(0) because of a good reason.
Then, you call your macro when you want to print the error:
if (error) {
DISPLAY_ERR(error_info);
/* more statements if needed */
}
I am assuming that error_info has been defined somewhere. If not, or if you don't want to, then you can change your macro definition and use:
#define DISPLAY_ERR() \
do \
{ \
ERR_INFO error_info;
ErrorInfo(&error_info); \
fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); \
} while(0)
if (error) {
DISPLAY_ERR();
/* more statements if needed */
}
There's a couple of ways you could do this. You could use the comma operator:
#define DISPLAY_ERR(error_info) (ErrorInfo(&(error_info)),(error_info).msg)
...or you could change the ErrorInfo() function so that it's return value is the pointer you pass it:
#define DISPLAY_ERR(error_info) (ErrorInfo(&(error_info))->msg)
(and a few more options besides).
Are you trying to create a macro which "returns" a value? In C++ you can use the comma operator , to evaluate the left expression and then return the right expression. You can do the same in C, too.
(foo(var), var.field) // foo(...)is evaluated first,
// then second expression is returned
also
DISPLAY(message) // Pass an argument to macro
You need to make it work like a function call, so it can be used anywhere a function call can, except with no value returned. You also need to mark the ends of intermediate lines with a backslash. And the 'do { ... } while (0) idiom is useful in this context:
#define DISPLAY_ERR() do { ERR_INFO error_info; ErrorInfo(&error_info); \
fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); } while (0)
The error_info variable is local to the block, so you don't have to remember to declare it in the functions where you use the macro (or have it as a file static or, perish the thought, global variable).
Note that this code does not return a value, but it can be used anywhere in a function that a void expression could be used:
if (somefunc() != 0)
DISPLAY_ERR();
else if (anotherfunc() != 0)
DISPLAY_ERR();
else
do_something_useful_after_all();
Etc.
I would still want to make sure I measured the overhead of using a regular function versus having the function-like macro. Used often enough, you might be still be better off with a real function.

Resources