开发者

Evaluate macro parameter once only

开发者 https://www.devze.com 2023-01-13 23:38 出处:网络
In the following code, whatever is passed as retval is evaluated as given for every use of that token.

In the following code, whatever is passed as retval is evaluated as given for every use of that 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 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);

Evidently I don't want to execute the statement inode && file_truncate(inode, len); more than once. How can I ensure that the given tokens are evaluated before being pasted helter-skelter?

Update

I believe I have good reason to use macros here. Where possible, c开发者_运维百科ode is put into real functions (such as util_cpfs_exit) which are invoked from a set of macros I'm using. The macros vary based on the return type: in C++ I'd have explicit templates to handle this.


As your macro vary on the return type, you can evaluate the retval expression and store it in a variable of the right type inside the first level of macro then use this variable. ie:

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

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

In your exemple you'll get:

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

Looks fine.

PS: as a sidenote if you always use _CPFS_RETURN indirectly through another macro following the above model, there is no need to protect it by a do { } while (false);. Also, putting a semi-colon after the while(false) removes most of the interest of using it... that may be a good example of why C macros are dangerous and hides easy pitfalls. Not that I dislike macros, quite the contrary. I'm from the (probably rare) kind of people that would prefer C macros to be enhanced to bypass their current limitations to become really cool (and no, C++ templates are not enhanced macros, they are something completely different).


I would recommend that you evaluate the condition first.

i.e.

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

Other than that may advice would be to steer well clear of macros, they seem unnecessary in this instance, use functions instead.


Write a function instead of using a macro. In this case, where you want to build a return statement in, you might be better off just writing the code explicitly instead of relying on a macro to hide what you're doing.


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

0

精彩评论

暂无评论...
验证码 换一张
取 消