News for hackers. Stuff that matters.
Re:Let the Compiler Do the Work by kstenerud on Tuesday January 07, 2020 @05:56AM (#21978821)
"sqr is a place where one might be tempted to use a macro in C, but writing such a macro in a way that x doesn't get evaluated twice is tricky."

Slightly off-topic, but it's important to point out that in modern C, implementing such a function as a macro is always a mistake. You'd do it as an inline function.

Macros in modern C should only be used for code generation (for DRY). If the language supports doing it without a macro, then do it without a macro.

Re:Let the Compiler Do the Work by flohofwoe on Tuesday January 07, 2020 @07:57AM (#21979480)
...or link with LTCG / LTO, this automatically considers all functions for inlining across compilation units, no matter if they are marked as inline or not. For C code this is preferable IMHO because it allows to keep declaration and implementation code strictly separate, inline functions muddy that line because they must live in headers.
Re:Let the Compiler Do the Work by pingyong on Tuesday January 07, 2020 @08:06AM (#21979549)
While I vastly prefer this workflow wise, for large projects it can increase compile time drastically. https://lwn.net/Articles/744507/

For projects that will never have more than ~1 million LOC it's probably fine. Less than ~100K, definitely preferable.

Re:Let the Compiler Do the Work by mikepurvis on Tuesday January 07, 2020 @10:36AM (#21980911)
What about ThinLTO? The idea of having a overnight full build that creates some kind of cache which incremental builds throughout the day can use to do fast whole-binary LTO seems like the best of both worlds.

Basically just wondering if anyone has first hand experience using this kind of thing on a large project.

Re:Let the Compiler Do the Work by rwem on Tuesday January 07, 2020 @11:28AM (#21981450)
ThinLTO was written by people responsible for peak optimization of very large programs at Google. I honestly can’t call it “fast” but it’s a lot faster than GCC LTO. You normally only peak-optimize your release builds so it’s not like developers are sitting there counting the seconds.
Re:Let the Compiler Do the Work by derefr on Tuesday January 07, 2020 @12:34PM (#21982229)
> You normally only peak-optimize your release builds so it’s not like developers are sitting there counting the seconds.

Sometimes you do want to debug a release build because the optimizations have gone wrong, though. In that case, it's helpful if release builds build quickly, and especially if they rebuild quickly as you turn various sub-optimization flags on and off.

Re:Let the Compiler Do the Work by rwem on Tuesday January 07, 2020 @12:45PM (#21982381)
Yes, and sometimes you want to validate a performance change and you need the release build to run in the benchmark fixture, and then it's irritating that the build takes forever but what can be done? ThinLTO's real benefit is that it uses so much less memory than legacy LTO and can be applied to larger programs (like Chrome).
Re:Let the Compiler Do the Work by Avamander on Tuesday January 07, 2020 @08:32AM (#21979718)
Those large projects benefit the most from LTO as well though.
Re:Let the Compiler Do the Work by jnordwick on Tuesday January 07, 2020 @07:01AM (#21979145)
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.
Re:Let the Compiler Do the Work by gallier2 on Tuesday January 07, 2020 @07:20AM (#21979253)
Since C11 there's _Generic which allows to do it. Using macros in that case is strongly advised (or else it would be very verbose).
Re:Let the Compiler Do the Work by simias on Tuesday January 07, 2020 @08:35AM (#21979750)
That'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

Re:Let the Compiler Do the Work by oefrha on Tuesday January 07, 2020 @11:04AM (#21981212)
> 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)
Re:Let the Compiler Do the Work by jlokier on Tuesday January 07, 2020 @11:46AM (#21981659)
First, 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.

Re:Let the Compiler Do the Work by oefrha on Tuesday January 07, 2020 @01:54PM (#21983266)
When 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.
Re:Let the Compiler Do the Work by simias on Tuesday January 07, 2020 @05:19PM (#21985706)
I 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

    #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);
Re:Let the Compiler Do the Work by oefrha on Tuesday January 07, 2020 @08:54PM (#21987468)
That’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.)
Re:Let the Compiler Do the Work by GlitchMr on Tuesday January 07, 2020 @08:20AM (#21979635)
You don't need macros for generic code either :), Rust has generics.

    fn sqr<T: Copy + Mul>(x: T) -> T::Output {
        x * x
    }
Re:Let the Compiler Do the Work by LandR on Tuesday January 07, 2020 @06:15AM (#21978915)
Same advice in LISP.

Don't use a macro where a function will do.

Re:Let the Compiler Do the Work by petrogradphilos on Tuesday January 07, 2020 @11:34AM (#21981508)
Never use a macro to do an inline function’s job.
Re:Let the Compiler Do the Work by nguoi on Tuesday January 07, 2020 @07:26AM (#21979293)
Inline was added in C99, which MSVC still doesn't support entirely. If this has to be taken into account when you choose what standard to use for your codebase, that's a quarter of a century trickle down for features to reach the consumer.

I hope I get to use C2x* before I retire.

*postmodern C?

Re:Let the Compiler Do the Work by flohofwoe on Tuesday January 07, 2020 @07:54AM (#21979463)
The Microsoft C compiler actually has pretty good C99 support since VS2015 (e.g. inline is definitely supported).

AFAIK the only non-supported C99 features in the C compiler are VLAs (optional since C11 anyway), and type-generic macros (those would be good to have though).

Of course it would be nice if Microsoft gave the C compiler a bit more love, especially since it's much less work keeping a C compiler uptodate than a C++ compiler, but at least we got "most of C99".

Re:Let the Compiler Do the Work by jlokier on Tuesday January 07, 2020 @11:51AM (#21981716)
The quarter of a century thing does not apply to "inline".

Although inline was added in C99, it was already an extremely widely supported extension in mainstream compilers, even since the C89 days, when we just called it "ANSI C".

MSVC has supported inline for a long time, long before it started supporting other C99 features.

Re:Let the Compiler Do the Work by nguoi on Tuesday January 07, 2020 @12:21PM (#21982060)
That doesn't matter if features you're able to used are gated on the standard you use. If the standard you choose is based on what your target platforms 'support': no inline for you.
Re:Let the Compiler Do the Work by jlokier on Tuesday January 07, 2020 @12:49PM (#21982428)
It seems weird to decide that you won't use features because they are in a public standard that your target platform doesn't support, even though your target platform fully supports those features themselves.

I could understand the concern if it was about portability to other target platforms, or keeping the option of doing so. But in that case, the public standard your current target supports is irrelevant.

Re:Let the Compiler Do the Work by nguoi on Wednesday January 08, 2020 @07:09AM (#21990645)
It happens. Imagine you decide on the MS-compatible bits C99, then the team naturally picks up new people and loses the ones who made the decision. Eventually, people will know the standard is C99 from the build system but not the reason behind the decision.

So they add a feature not supported by MSVC and don't learn that it doesn't work until someone else tries to build on Windows.

If you choose to use features based on whether they work or not, you don't need to choose a standard at all. But that loses you all of the guarantees a standard provides.