How to make the first macro call different from all the following?

It may be very simple, but I cannot find a good answer. How can I make a macro representing a specific value first and then another?

I know this is unpleasant, but I need it to implicitly declare the variable for the first time, and then do nothing. This variable is required for other macros that I implement.

Should I use "argument preview"?

What you need to know is the fact that I'm generating code:

#define INC_X x++ //should be declared if needed to #define PRINT_X printf("VALUE OF X: %d\n", x) int func() { [...] INC_X; [...] INC_X; [...] PRINT_X; [...] } 
+4
source share
7 answers

As far as I know, this is not possible. I don’t know how to expand a macro to control how another macro - or myself - will be expanded after. C99 introduced _Pragma so that #pragma can be done in macros, but there is no equivalent for #define or #undef .

+3
source
 #include <stdio.h> #define FOO &s[ (!c) ? (c++, 0) : (4) ] static int c = 0; const char s[] = { 'f', 'o', 'o', '\0', 'b', 'a', 'r', '\0' }; int main() { puts(FOO); puts(FOO); return 0; } 

Does it help above?

+2
source

In appearance, you can try if Boost.Preprocessor contains what you are looking for. Look at this tutorial

http://www.boostpro.com/tmpbook/preprocessor.html

from the excellent C ++ template metaprogramming book.

+1
source

With editing I will answer. This requires your compiler to support __FUNCTION__ , which MSVC and GCC do.

First write a set of functions that maps strings to integers in memory, they are all stored in some global instance of the structure. This remains as an exercise for the reader, functionally it is a hash map, but I will call the resulting instance of "global_x_map". The get_int_ptr function get_int_ptr defined as returning a pointer to an int corresponding to the specified string, and if it does not already exist to create and initialize it to 0. reset_int_ptr just assigns 0 to the counter at the moment, you will see later why I did not just write *_inc_x_tmp = 0; .

 #define INC_X do {\ int *_inc_x_tmp = get_int_ptr(&global_x_map, __FILE__ "{}" __FUNCTION__); \ /* maybe some error-checking here, but not sure what you'd do about it */ \ ++*_inc_x_tmp; \ } while(0) #define PRINT_X do {\ int *_inc_x_tmp = get_int_ptr(&global_x_map, __FILE__ "{}" __FUNCTION__); \ printf("%d\n", *_inc_x_tmp); \ reset_int_ptr(&global_x_map, _inc_x_tmp); \ } while(0) 

I chose the separator "{}" on the grounds that it will not occur in the changed function name of C - if for some reason your compiler can put this in the changed function name, then, of course, you will have to change it. Using something that cannot appear in the file name on your platform will also work.

Note that functions that use the macro are not returned, so this is not exactly the same as defining an automatic variable. I think it is possible to make him a repeat participant. Pass __LINE__ as an additional parameter to get_int_ptr . When the record is created, save the value __LINE__ .

Now the map should store not only int for each function, but also a stack from int. When it is called with this value of the first visible line, it must push a new int onto the stack and return a pointer to that int after whenever it calls this function with any other value of the line. When reset_int_ptr is reset_int_ptr , instead of setting the counter to 0, it must pop the stack so that future calls return the previous int.

This only works, of course, if the "first" call to INC_X is always the same, it is called only once during the execution of the function, and this call does not appear on the same line as the other call. If it is in a loop, if() , etc., this happens incorrectly. But if it is inside a block, then declaring an automatic variable will also go wrong. It also works only if PRINT_X is always called (check your early errors), otherwise you will not restore the stack.

It may sound like a crazy engineering part, but essentially it is how Perl implements variables with a dynamic scope: it has a stack for each symbol name. The difference is that, like C ++ with RAII, Perl automatically pops this stack when it leaves the scope.

If you want it to be thread safe as well as repetitive, then create global_x_map thread-local instead of global.

Edit: this identifier __FILE__ "{}" __FUNCTION__ is still not unique if you have static functions defined in the header files - different versions in different TUs will use the same counter in the version without re-entering. This is normal in replay, I think. You will also have problems if __FILE__ is the base and not the full path, since you can get a collision for static functions with the same name as in files with the same name. This bounces even from a repeated application. Finally, not one of them has been verified.

+1
source

How about the fact that macroC # define some flag at the end of its execution and check this flag first?

 #def printFoo #ifdef backagain bar #else foo #def backagain 

You need to add some \ chars to make it work - and you probably don't want to do this compared to the built-in func ()

0
source
  #define FOO __COUNTER__?  bar: foo

Edit: delete all unnecessary codes

0
source

An alternative to some of the methods proposed so far would be to use function pointers. This may not be exactly what you are looking for, but they can still be a powerful tool.

 void foo (void); void bar (void); void (*_func_foo)(void) = foo; void foo (void) { puts ("foo\n"); } void bar (void) { puts ("bar"\n"); } #define FOO() _func_foo(); \ _func_foo = bar; int main (void) { FOO(); FOO(); FOO(); return 0; } 
0
source

Source: https://habr.com/ru/post/1304153/


All Articles