Hacker News new | past | comments | ask | show | jobs | submit login
C preprocessor tricks, tips, and idioms (2015) (github.com/pfultz2)
78 points by Pete_D on Aug 23, 2019 | hide | past | favorite | 12 comments



I used to use all sorts of preprocessor tricks in my C code. I eventually made an effort to eliminated all preprocessor use in the code (except for #include, where there was no alternative).

The result was surprisingly pleasing. The code looked much nicer without all the #'s breaking up the indentation, and it made C look like a more modern language :-)


There are lots of horrific weapons like this to ever torment the universe. e.g. http://p99.gforge.inria.fr/p99-html/index.html


I work in C all day every day. It's fine, I get by. And then I run into macros. Fucking macros.

Hey guess what REQUEST and REQUEST_FIXED_SIZE do here: https://gitlab.freedesktop.org/xorg/xserver/blob/master/dix/... Did you guess "declares a new variable called 'stuff'" and "returns early", respectively?

Do you think dixAllocateObjectWithPrivates is a function here? https://gitlab.freedesktop.org/xorg/xserver/blob/master/dix/... Haha, think again! Macro.

Guess what fbGetPixmapBitsData does here: https://gitlab.freedesktop.org/xorg/xserver/blob/master/fb/f... Did you guess assign values to the latter 3 arguments, two of which aren't even passed by reference??

I'm picking on the xserver because it's my most memorable encounter with bad macros, but agh. Agh!


Honestly that's both poor naming and also abuse of macros combined with poor tooling (lack of syntax highlighting for macro usage for the reader). They do make it easier to shoot yourself in the foot, but they also let you do useful stuff that you simply couldn't do otherwise. The trouble is mostly teaching people to only use them for such purposes and not for anything else.


I think it’s hard to blame any macro system that operates at the source code level for this kind of thing since it’s basically impossible to prevent this type of abuse. The C preprocessor doesn’t enable it any more or less than others.


Where do you work that you get to work in C all day every day? I haven’t been able to do that in over 25 years. Sometimes I miss those days. Then you see one of these stupid macros!


Come to automotive, you can program in c90 all the live long day


See my profile. We're hiring.


I have a problem with:

  ProcQueryExtension(ClientPtr client)
  {
    xQueryExtensionReply reply;
    int i;

    REQUEST(xQueryExtensionReq);

    REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);

    reply = (xQueryExtensionReply) {
      .type = X_Reply,
      .sequenceNumber = client->sequence,
      .length = 0,
      .major_opcode = 0
    };

What's wrong with:

  ProcQueryExtension(ClientPtr client)
  {
    xQueryExtensionReply reply = {
      .type = X_Reply,
      .sequenceNumber = client->sequence,
      .length = 0,
      .major_opcode = 0
    };
    int i;
    REQUEST(xQueryExtensionReq);
    REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
Can't we define and initialize a structure any more without some damned compound literals?

> Did you guess assign values to the latter 3 arguments

In C++, functions do that.

   void assign(int &target, int val) { target = val; }

   assign(x, 42);


>In C++, functions do that.

GP means 'they do that unexpectedly.' In your C++ code, your function doesn't just up and decide to make changes to the parameters; `target` is a reference and therefore the caller should expect it to be modified. In GP's case, he's presumably complaining that the macro definition for `fbGetPixmapBitsData` gives no indication that the last three arguments will have their addresses taken to be passed elsewhere.


"In your C code, your macro doesn't just up and decide to make changes to the parameters. TARGET is a macro parameter, and therefore the caller should expect it to be modified."

Sorry, you don't hold water. A C++ function can be edited from a pure function to one with non-const, mutated ref parameter, and some (perhaps all) uses of that function in the program will still compile. That counts as "just up and decide to make changes to the parameters".

You have to read the definition to see what is going on, just like with a macro.

> macro definition for `fbGetPixmapBitsData` gives no indication that the last three arguments will have their addresses taken to be passed elsewhere.

If there is no indication, then it's not that macro itself that is arranging the mutation syntax. It must be expanding into something that looks innocent. E.g. we can have a macro over my C++ assign function above:

   #define asn(x, y) assign(x, y)
Sure, the macro definition doesn't give a clue because it expands to something that looks like another function or macro call, which we then have to understand. The C++ function is the culprit that is mutating x, not the macro.

It's true that with macros, we can build up a labyrinth of expansions where such a thing can hide more easily; whereas if we use nothing but C++ functions, the one we are calling has to steal that address, not any of its delegates.


It's difficult to justify the macro aspect of the preprocessor, there are a thousand horror stories for every questionably good macro use-case. The only somewhat respectable macro definition usage I recall from my C++ days was type aliasing to support multi-platform build targets. But even that is hard to rationalize outside the standard libraries.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: