• (nodebb)

    The first clue that nothing is well is the function signature. Takes no parameters, returns nothing, and yet it's name implies that it does something. That's enough to indicate that global variables and side-effects up the wazoo will be your next step on your journey to ...

    Hey, wait, why am I in this handbasket, and why is it getting hot all of a sudden?

  • Jaloopa (unregistered)

    I still don't understand why macros exist rather than just defining a function. They're a subtly different language feature that's easy to mess up. What do they add over normal functions that makes it worth the extra complexity?

    I'm talking about C/C++ macros specifically here. I know languages like lisp use the term for something related but more integrated into the language

  • Sauron (unregistered)

    #define WTF true

  • Kythyria (unregistered) in reply to Jaloopa

    Mostly history. Nearly everything cpp is used for now could be replaced by some other language or compiler feature, but when C was designed, a single relatively simple tool that does all of them jankily and could in principle be bodged to other uses, was deemed preferable to the complexity/performance impact of those other features, especially on 1970s hardware.

    This particular use of macros smells of using them to emulate inlining, which modern compilers do very aggressively, provided the function definition is available (which means link-time optimisation or sticking it in a header).

  • (nodebb) in reply to Kythyria

    static inline functions do very well at being inlined in modern C, at least with any compiler you're actually likely to use. You can even have multiple definitions of them in different files without things breaking; you get similar benefits to what you have at the saner end of templating in C++. There are things you can do with macros which those functions can't do, but it's often a good idea to make as much as possible of the more complicated parts be functions.

  • (nodebb)

    Also, GISs are high WTF territory. I didn't know anyone would be mad enough to interface to them in C.

  • dpm (unregistered)

    macros that include some error handling

    When you reach these words, you can confidently stop reading the article, knowing that no greater WTF is possible.

  • Peter Smith (github) in reply to Jaloopa

    Why macros and not functions? If you're a gray beard, functions used to have two big problems.

    Firstly, functions polluted the global namespace. For small programs, that's not a problem. For a big program, it's a big problem. Worse, C didn't always support long function names (see IEFBR14 for a similar problem with function name :-) ).

    Secondly, functions were always slow -- this is before inlining functions was a thing,

    And lastly: macros can change the state of function-local variables, and functions can't. done well, this is a help; done poorly, it's leads to a mess of code.

    Addendum 2023-11-16 11:25: Edit: I wrote "pollute the global namespace" -- is more nuanced than that, but it's close enough for rock-and-roll

  • (nodebb) in reply to Peter Smith

    And lastly: macros can change the state of function-local variables, and functions can't. done well, this is a help; done poorly, it's leads to a mess of code.

    And more to the point, it's very often done somewhere in-between, but the acceleration from "this is a help" towards "leads to a mess of code" is extremely fast.

  • (nodebb) in reply to Jaloopa

    In the early days of C, the compiler was a lot more primitive than modern compilers and the language itself lacked features.

    For example:

    • There was no way to define a constant so preprocessor macros was used instead.

    • As others have said, there was no function inlining so for small functions, using a macro instead represented an optimisation

    • All arguments are call by value. A function couldn't change something passed to it in such a way that the change was visible to the caller except by passing a pointer and dereferencing it inside the callee. Macros let you do that without the added syntax and overhead.

    • You could also use macros to hide messy implementation details e.g. system calls or non portable stuff without the overhead of a function call

    • If you didn't like C, you could use macros to pretend you weren't programming in C. OK this one is stretching the point a bit. Try tracking down a copy of the original source for the Bourne shell to see what I mean. If you do find a copy, I warn you, you're going to need some eyeball bleach as well. It makes most of the WTFs you read here seem somewhat petty.

  • (nodebb) in reply to jeremypnet

    All arguments are call by value. A function couldn't change something passed to it in such a way that the change was visible to the caller except by passing a pointer and dereferencing it inside the callee. Macros let you do that without the added syntax and overhead.

    I agree in the overhead being a potential problem in older compilers and hardware. But the added syntax I consider, if anything, an advantage...

    Working with Fortran, I despise "pass by (mutable) reference", when there is nothing on the call-site marking that fact.

    Addendum 2023-11-16 15:17: I forgot that seeing a & in C doesn't tell you if it is a pointer-to-const or a pointer-to-mutable, so the extra syntax actually doesn't add value in that regard...

  • Worf (unregistered)

    Macros are still used today to populate arrays of structures.

    Let's say you have a structure that has to hold a lot of data at runtime, but only needs to hold a bit of data at compile time - perhaps it's a list of global variables, or maybe it's a mapping of names to variable and string types.

    E.g., you want to define something that maps a variable to a string, so you could say match it. You could define a structure to have both like { { variable1, "variable1" }, { variable2, "variable2" }, ... }

    but that gets tedious and you may end up with a desync between the variable and the name. A clever macro can easily be able to do that AND avoid a possibility of the name and variable desync:

    #define PARAM(name) { name, #name } which gets you

    { PARAM(variable1), PARAM(variable2) }

    Windows uses a lot of it to hide the fact it likes to overload variables - return values often have a return code (lower 16 bits) plus an origin and domain code (upper 16 bites). Macros are used to extract those values in a readable way rather than random looking shifts and binary operations.

  • (nodebb)

    Without C macros, we would not have had MFC and ATL.

    Ok I guess I'm not making a positive point for them here.

  • (nodebb) in reply to Ralf

    Hey, those were great for their time.

  • (nodebb)

    I remember macros also being used for debug statements, so that if some flag wasn't enabled then the statements were not compiled into the code at all.

  • Gnasher729 (unregistered)

    All input to interpolate is global. So you just pass param and el as parameters to el and you are done except for the error handling. And since it is static, you have the source file where it is called.

  • handbasket (unregistered) in reply to jeremypnet

    Eyeball bleach indeed. loop/pool made me chuckle though. Maybe this handbasket has descended further than we thought.

    Anyone for some C horror can find it here: http://web.archive.org/web/20090129181202/http://minnie.tuhs.org/UnixTree/V7/usr/src/cmd/sh/

    mac.h is the source of this inferno http://web.archive.org/web/20090125153700/http://minnie.tuhs.org/UnixTree/V7/usr/src/cmd/sh/mac.h.html

  • cricketlinesguru (unregistered) in reply to Steve_The_Cynic
    Comment held for moderation.
  • cricketlinesguru (unregistered) in reply to Steve_The_Cynic
    Comment held for moderation.
  • (nodebb) in reply to Steve_The_Cynic
    Comment held for moderation.
  • (nodebb)
    Comment held for moderation.
  • Craig (unregistered) in reply to Jaloopa
    Comment held for moderation.

Leave a comment on “Mapro”

Log In or post as a guest

Replying to comment #:

« Return to Article