Complex one-line conditional checksum definitions - c

Taking up this code:
typedef enum CHECKSUM { DENY = 0, ALLOW = 1 } checksum;
#define terminal(x, str) static checksum* terminal_##x; { if(!strcmp(#str, "static")) { static checksum local = ALLOW; terminal_##x = &local; } else { checksum local = DENY; terminal_##x = &local; } }
What I want that code to do is define a macro function with two parameters x for name and str for a specific type. The macro function declares a static checksum* with the name terminal_ concatenated with the name x. Then it opens a new scope and stringify the specific type str and use a strcmp to check if it equals static. If so.. then it declares a variable type static checksum, initialized with ALLOW and makes the declared pointer to point to it, if it is not equal then it declares a variable type checksum, initialized with DENY and set the pointer to point to it.
Then we can call the macro like that:
int main(void)
{
int i = 0;
while(*terminal_name == ALLOW) { terminal(name, static) if(i > 200) { *terminal_name = DENY; } i++; }
return 0;
// Note that this is only an example usage. The real usage of this is far more long and complicated.
}
The code is well compiled on C89 and it causes no errors nor warnings. On a first view.. it works.
But as you can see by yourself.. it looks really suspicious.
Is that the correct way I am doing it?
Please ask if you are in trouble understanding something.

It's hard to say if the macro is reasonable or a bad idea without knowing more about your program.
Stylistically, you can use backslashes to split the macro up into multiple lines. That'll make it a lot more readable and less "suspicious".
#define terminal(x, str) \
static checksum* terminal_##x; \
{ \
if (!strcmp(#str, "static")) { \
static checksum local = ALLOW; \
terminal_##x = &local; \
} \
else { \
checksum local = DENY; \
terminal_##x = &local; \
} \
}
Using strcmp to decide whether to use static or not really rubs me the wrong way. That's a runtime check influencing a compile-time decision. I would suggest making two separate macros, say LOCAL_TERMINAL and STATIC_TERMINAL, rather than keying off of a macro argument.
#define LOCAL_TERMINAL (x) checksum terminal_##x = DENY
#define STATIC_TERMINAL(x) static checksum terminal_##x = ALLOW

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;
}

replace a function with constant string argument with macro in C

In a project I work on we have some utility functions which taking 2 arguments,one is address to write and second is value to write.
Lets use a simple example:
enum {
ADDR1 = 0x1000,
ADDR2 = 0x1500,
....
};
void Hardware_write_reg(ADDR,val)
{
switch ADDR {
case ADDR1 : abc.x = val; break;
case ADDR2 : abc.f = val; break;
.....
.....
}
This function "Hardware_write_reg" are called in many number of times in many files throughout the project with different ADDR and values as arguments.
Now,I need to remove the calls to "Hardware_write_reg" and write directly to struct members.
An example,Function1() below need to be changed
Before change:
Function1()
{
Hardware_write_reg(ADDR1,val1);
Hardware_write_reg(ADDR2,val4);
Hardware_write_reg(ADDR7,val6);
.....
}`
After change:
Function1()
{
abc.x = val1;
abc.f = val4;
abc.s = val6;
.....
}
I cannot do it manually,because many numerous calls to Hardware_write_reg() in multiple files.
I tried with C Macro,like this;but could not get expected result
#define Hardware_write_reg(ADDR1,A) do{\
abc.x = ((A));\
}while(0)
#define Hardware_write_reg(ADDR2,B) do{\
abc.f = ((B));\
}while(0)
Basically,I want to replace (at compile time)
1) Hardware_write_reg(ADDR1,val1); function call to abc.x = val1; with a macro
2) Hardware_write_reg(ADDR2,val2); function call to abc.f = val2; with a macro
3)....
Any help from C-Guru's would be appreciated!
You could define a bunch of macros which does
#define target_ADDR1 abc.x
#define target_ADDR2 abc.f
#define CONCAT2(a, b) a##b
#define Hardware_write_reg(ADDR,val) CONCAT2(target_,ADDR) = val
so that
Hardware_write_reg(ADDR1,42);
is replaced by
target_ADDR1 = 42;
and thus
abc.x = 42;
is what you get.
Disclaimer: I haven't tested it, but I am quite sure this should work.
Instead of programatically solving this you can try regular expression replacement which included in most of the text editors today. but here the problem is for each case in switch you have to modify regex for a bit. And you should not have any other Hardware_write_reg in your code.
search
Hardware_write_reg(ADDR1,val([0-9]+));
replace with
abc.x = val\1;
Also if you have many cases you can generate regex and replacement with a small script.
The only thing I could imagine that works for this case is you put the assignment operations into a switch statement
#define Hardware_write_reg(ADDR,A) do{\
switch((ADDR)) { \
case ADDR1: abc.x = ((A));\
case ADDR2: abc.f = ((A));\
...
} \
} while(0)
As the C Macros cannot guess the values of ADDR during compile time and hence cannot put appropriate structure member for each ADDR.
As you want replace the function call with the actual assignment statement. So it seems like the only way you can do it is to Find/Replace in the code. For this you can write a regular expression and find a replace using that. For instance for ADDR1:
Find the Regular Expression:
(Hardware_write_reg)[(](ADDR1)[,]([\w]*)[)];
And Replace it with:
abc.x = $3;
The above regular expressions are compatible in eclipse

Force function to accept specific definitions only?

I would like to force a functions parameters to accept only specific definitions. For example, consider #define OUTPUT 1, #define INPUT 0 and void restrictedFunction(int parameter); .
How would I force restrictedFunction(int parameter) to accept only OUTPUT or INPUT?
I would also like to take into consideration that another definition may have the same value, for example, #define LEFT 1 and #define RIGHT 0.
So in this case I would like restrictedFunction(int parameter) to be able to accept only OUTPUT and INPUT specifically.
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
void restrictedFunction(IO_Type parameter) { ... }
It doesn't absolutely force the use of the values (the compiler will let someone write restrictedFunction(4)), but it is about as good as you'll get.
If you truly want to force the correct type, then:
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
typedef struct { IO_Type io_type } IO_Param;
void restrictedFunction(IO_Param parameter) { ... }
In C99 or later, you could call that with:
restrictedFunction((IO_Param){ INPUT });
This is a compound literal, creating a structure on the fly. It is not entirely clear that the structure type really buys you very much, but it will force the users to think a little and may improve the diagnostics from the compiler when they use it wrong (but they can probably use restrictedFunction((IO_Param){ 4 }); still).
What this means is that your restrictedFunction() code should be ready to validate the argument:
void restrictedFunction(IO_Type io_type)
{
switch (io_type)
{
case INPUT:
...do input handling...
break;
case OUTPUT:
...do output handling...
break;
default:
assert(io_type != INPUT && io_type != OUTPUT);
...or other error handling...
break;
}
}
You could use an enum.
typedef enum TrafficDirection { INPUT = 0, OUTPUT = 1 } TrafficDirection;
restrictedFunction(TrafficDirection direction);
of course, this isn't perfect. You can still pass any int to it as long as you use a cast.
restrictedFunction((TrafficDirection) 4);
You don't get quite as much protection as you might like, but you can do:
enum func_type { INPUT, OUTPUT };
void restrictedFunction( enum func_type parameter );
You can use a wrapper to validate the argument:
#define restrictedFunction(x) do { \
static_assert((x) == INPUT || (x) == OUTPUT); \
assert(!strcmp(#x, "INPUT") || !strcmp(#x, "OUTPUT")); \
restrictedFunction(x); \
} while(0)
Notes:
This assumes restrictedFunction() returns a void. If it returns a value which you actually use, you'll need something like gcc's compound statement http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html. Or--better--you can use BUILD_BUG_ON_ZERO (see What is ":-!!" in C code?), which I keep forgetting about, because it doesn't seem to work with C++.
The do ... while(0) is to "swallow the semi-colon"; not really relevant here.
static_assert() is a compile-time assert; there are many variants available. Here is a link to one, https://stackoverflow.com/a/9059896/318716, if you don't have your own handy.
assert() is the standard run-time assert.
With gcc 4.1.2, and my version of static_assert(), you can replace the run-time assert() with a compile-time assert when the two !strcmp()'s are replaced with ==; see example below. I haven't tested this with other compilers.
x is only used once in the macro expansion, since the first four references are only used at compile-time.
When your actually define your function, you'll have to add parentheses to disable the macro expansion, as in:
void (restrictedFunction)(int x){ ... }
Also, if your code has a special case (whose code doesn't?) where you need to call restrictedFunction() with the argument foo, you'll need to write:
(restrictedFunction)(foo);
Here is a complete example, which puts a wrapper around the standard library function exit():
#include <stdlib.h>
#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum{EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}
#define exit(x) do { \
ASSERTM((x) == EXIT_SUCCESS || (x) == EXIT_FAILURE, value); \
ASSERTM(#x == "EXIT_SUCCESS" || #x == "EXIT_FAILURE", symbol); \
exit(x); \
} while(0)
int main(void) {
exit(EXIT_SUCCESS); // good
exit(EXIT_FAILURE); // good
exit(0); // bad
exit(3); // doubly bad
}
If I try to compile it, I get:
gcc foo.c -o foo
foo.c: In function 'main':
foo.c:17: error: enumerator value for 'symbol_ASSERT_line_17' is not an integer constant
foo.c:18: warning: division by zero
foo.c:18: error: enumerator value for 'value_ASSERT_line_18' is not an integer constant
foo.c:18: error: enumerator value for 'symbol_ASSERT_line_18' is not an integer constant

How to make a variable inside a function or macro-function that must be defined only one time?

I call CURRENT_DIR(see below) a lot of times in my program. Like the executable path don't change while the program is running, make no sense define it again each time that I call this function.
So, I'm looking for a solution that once this value has set, it should be not set again.
My current solution is: make a static variable with all values set to 0 and in an if-statement test check if the first character if non-null, if true, then set it. But it's looks like a inelegant.. maybe there is a better solution.. by using some model including macros, I do not know.
See the code:
#define CURRENT_DIR ({ \
static char buffer[MAX_PATH + 1] = { 0 }; \
if(buffer[0] != '\0') \
getcurrentdir(buffer, MAX_PATH); \
buffer; \
})
Instead of the gcc-specific expression statement, I'd use a function (possibly inlined if desired):
const char* currentDir(void)
{
static char buffer[MAX_PATH + 1] = { 0 };
if (buffer[0] == '\0')
{
getcurrentdir(buffer, MAX_PATH);
}
return buffer;
}
This has a few advantages:
It's more portable. (Of course, MAX_PATH and getcurrentdir would be platform-dependent.)
It has better type safety. If the string is meant to be constant, you don't want to allow clients to accidentally modify it.
(The gcc expression statement implementation is broken anyway. The static variable won't be reused across multiple CURRENT_DIR sites in the same scope, and the if test is backwards, so buffer will never be initialized to a non-empty string.)

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)

Categories

Resources