Calculate macro parameter only once

In the following code, everything that is passed as retval is evaluated as given for each use of this token.

 #define _CPFS_RETURN(commit, retval) do { \ util_cpfs_exit(commit); \ return retval; \ } while (false) #define CPFS_RETURN_BOOL(retval) do { \ _CPFS_RETURN(retval, retval); \ } while (false) 

For example, given the use of CPFS_RETURN_BOOL(inode && file_truncate(inode, len)); this is generated:

 do { do { util_cpfs_exit(inode && file_truncate(inode, len)); return inode && file_truncate(inode, len); } while (0); } while (0); 

Obviously, I do not want to execute the inode && file_truncate(inode, len); more than once. How can I guarantee that these markers will be evaluated before being inserted using the helper skelter?

Update

I believe that I have every reason to use macros here. Whenever possible, the code is injected into real functions (such as util_cpfs_exit) that are called from the set of macros that I use. Macros vary depending on the type of return value: in C ++, I would have explicit templates to handle this.

+4
source share
4 answers

Since your macro depends on the type of return value, you can evaluate the retval expression and store it in a variable of the correct type inside the first level of the macro, and then use this variable. i.e:

 #define CPFS_RETURN_BOOL(retval) do { \ bool _tmp_ = retval; _CPFS_RETURN(_tmp_, _tmp_); \ } while (false); 

If I understand well, this should be enough for your use case, and for other use cases you can use functions.

In your example, you will get:

 do { bool _tmp_ = inode && file_truncate(inode, len); do { util_cpfs_exit(_tmp_); return _tmp_; } while (0); } while (0); 

Looks nice.

PS: as a side element, if you always use _CPFS_RETURN indirectly through another macro, following the model above, there is no need to protect it with do { } while (false); . Also, adding a semicolon after while(false) eliminates much of the interest in using it ... this may be a good example of why C macros are dangerous and hide light traps. Not that I didn't like macros, quite the opposite. I am from (possibly rare) people who would prefer that C macros be expanded to circumvent their current limitations, to become really cool (and no, C ++ templates are not improved macros, they are completely different).

+3
source

Write a function instead of using a macro. In this case, when you want to build a return , you might be better off just writing the code explicitly, rather than relying on a macro to hide what you are doing.

+2
source

I would recommend evaluating the condition first.

i.e.

 bool val = inode && file_truncate(inode, len); 

Also, it might be a tip to avoid macros, they seem unnecessary in this case, use functions instead.

+2
source

Change the macro to a "static inline" function. In gcc, it runs as fast as a macro. http://gcc.gnu.org/onlinedocs/gcc/Inline.html

0
source

All Articles