5 ms·
The point for doing it as a macro is to be generic over types. In C++ you would do a template function, but no real option in C.
by jnordwick 7y ago
The point for doing it as a macro is to be generic over types. In C++ you would do a template function, but no real option in C.
- gallier2 7y agoSince C11 there's _Generic which allows to do it. Using macros in that case is strongly advised (or else it would be very verbose).
- GlitchMr 7y agoYou don't need macros for generic code either :), Rust has generics. fn sqr<T: Copy + Mul>(x: T) -> T::Output { x * x }
- simias 7y agoThat's true, there are many situations where you simply can't replace a macro with a function because of this fact. MIN/MAX is a common example, unless you want to have one specialized version for every type. Unfortunately there are always tradeoffs using macros for something like that, you either end up evaluating the parameters more than once or you have to introduce variables in the macro that may shadow existing variables. Some compilers have extensions to help with that: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
- oefrha 7y ago> you have to introduce variables in the macro that may shadow existing variables. You certainly don’t have to introduce the risk of shadowing existing variables. You just use the standard #define MACRO(x) \ do { \ /* Define whatever variables you like */ \ /* Do things... */ \ } while (0)
- jlokier 7y agoFirst, you can't do that for the macros like MIN/MAX mentioned in the comment you just replied to, and sqr mentioned earlier. Second, you still risk shadowing existing variables, even if you make an effort to use "unlikely" names for the locals such as "___my_macro_secret_variable_1", if the macro might be used in one of its own arguments. For example MACRO(MACRO(x)). If that sounds unlikely, consider MAX(a,MAX(b,c)), which is likely to happen eventually, if your codebase uses such macros or if they are part of a library.
- oefrha 7y agoWhen you decide to define new variables you have already decided to write more than just an expression (which by definition can’t contain a statement), so “you can’t do that for...” is a moot point. And since it’s not an expression, it’s not gonna appear as its own argument, unless you’re using more advanced substituting a whole block trick which is not what the do while(0) idiom is for.
- simias 7y agoI can't make sense of what you're saying. See the page I linked in my previous post for an example of what we're talking about: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html #define maxint(a,b) \ ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) >Note that introducing variable declarations (as we do in maxint) can cause variable shadowing [...] this example using maxint will not [produce correct results]: int _a = 1, _b = 2, c; c = maxint (_a, _b);
- oefrha 7y agoThat’s a GNU C extension. I don’t write non-portable code like that. (Okay, I didn’t notice the link in your previous post, so I was basically replying to the wrong thing.)