Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

As a side note, these days you can fake named arguments in C, if you’re OK with every argument being 0 by default:

  // Declaration:
  void plot(float xlo, float xhi, float ylo, float yhi, float xinc, float yinc);
  struct plot_a { float xlo, xhi, ylo, yhi, xinc, yinc; };
  static inline void plot_i(struct plot_a _a) {
      // inline thunk to allow arguments to be passed in registers
      plot(_a.xlo, _a.xhi, _a.ylo, _a.yho, _a.xinc, _a.yinc);
  }
  #define plot(...) (plot_i((struct plot_a){ __VA_ARGS__ }))

  // Call:
  plot(alo, ahi, blo*2.0, bhi*2.0, .yinc = y, .xinc = f(x+z));


Note: this breaks if you want to pass struct literals:

   plot((myfoo){x,y})
Macros will take the struct literals as multiple parameters:

    plot(
      .arg0=(myfoo){x,
      .arg1=y}
    )
C macros are best left unused when possible.


Nope! In general, that can be a problem, but not for this specific technique:

  $ cpp -P
  void plot(float xlo, float xhi, float ylo, float yhi, float xinc, float yinc);
  struct plot_a { float xlo, xhi, ylo, yhi, xinc, yinc; };
  static inline void plot_i(struct plot_a _a) {
      // inline thunk to allow arguments to go in registers
      plot(_a.xlo, _a.xhi, _a.ylo, _a.yho, _a.xinc, _a.yinc);
  }
  #define plot(...) (plot_i((struct plot_a){ __VA_ARGS__ }))
  
  plot((myfoo){x,y})
  plot(.yinc=(myfoo){x,y})
  ^D
  [...]
  (plot_i((struct plot_a){ (myfoo){x,y} }))
  (plot_i((struct plot_a){ .yinc=(myfoo){x,y} }))
You could argue this is excessively clever, but when you need it, you really need it, so it could deserve known idiom status in the right situation.


> You could argue this is excessively clever, but when you need it, you really need it

I've probably written millions of lines of C so far, and I don't think I have ever needed it.


The usual workarounds are a stateful API (e.g. Cairo, OpenGL, or Windows GDI), passing a structure explicitly (oodles of examples in Win32, e.g. RegisterClass or GetOpenFileName), or a twiddling an object that’s actually just a structure dressed up in accessor methods (IOpenFileDialog).

There could be reasons to use one of those still (e.g. extensibility while keeping a compatible ABI, as in setsockopt, pthread_attr_*, or arguably posix_spawnattr_*). But sometimes you really do need a finite, well-known but just plain large number of parameters that mostly have reasonable defaults. Old-style 2D APIs to draw and/or stroke a shape (or even just a rectangle) are the classic example. Plotting libraries (in all languages) are also prone to this. It does seem like these situations are mostly endemic to specific application areas—graphics of all kinds first of all—but that doesn’t make them not exist.

If you don’t want to use function-like macros for anything ever even if this particular one works, that’s a valid position. But it does work, it does solve a real problem, and it is less awkward at the use site than the alternatives.


With large numbers of parameters, it's almost always more readable to use a config struct. Especially since often, you want to collect configuration from multiple sources, and incrementally initializing a struct that way is helpful.


C macros are best left unused when possible.

Blame the committee for failing to specify an obvious and widely-demanded feature like named parameters.

The only explanation is that the people in charge of the language don't write much code.


There are a lot of syntactic sugar improvements the committee could make that they simply refuse to. Named parameters and function pointer syntax are compile-time fixes that would have zero runtime costs, yet it's 2024 and we've hardly budged from ANSI C.


Exactly. I actually think default parameters are hazardous without named-parameter support. When they added one, IMO they should have added the other as well, so that you can specify exactly which non-default parameters you're passing.


I think this is more an appeasement of the C++ committee because they don't like the order of evaluation to be ambiguous when constructors with side effects come into play. Witness how they completely gimped the primary utility of designated initializers with the requirement to have the fields in order.


Or they do and don’t want to learn stuff as “everything can be done the old way anyway”


Say that to the Linux kernel or any embedded system


I've written both kernel code and embedded systems. It's easier to maintain the code when the preprocessor is avoided.


Pretty Neat.

Have a link to any articles/sites/books which has a compendium of more tricks ?




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

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

Search: