Hacker News new | ask | show | jobs
by yokohummer7 2197 days ago
> %n takes a pointer and writes (!!) the number of bytes printed so far.

> Okay, everyone probably knows this. Let's get a bit more advanced.

Ok, but I didn't know about that. What's the use?

5 comments

One use is aligning outputs:

  char *prefix = "example";
  char *line1 = "line 1";
  char *line2 = "line 2";
  printf("%s: %n%s\n", prefix, &n, line1);
  printf("%*s%s\n", n, "", line2);
will output

  example: line 1
           line 2
That’s a bit more robust than using strlen(s)+2, where you have to keep that magic constant 2 in sync with ": ". Moving ": " to a variable and using strlen(s)+strlen(separator) would fix that, though (at the price of speed, unless you’ve a compiler that optimizes that away)
> That’s a bit more robust than using strlen(s)+2

strlen wouldn't even be an option if you were formatting something that's not a string e.g.

    int n;
    int prefix_num = 23;
    char *line1 = "line 1";
    char *line2 = "line 2";
    printf("example %d: %n%s\n", prefix_num, &n, line1);
    printf("%*s%s\n", n, "", line2);
This only works if you're not dealing with Unicode, where the number of bytes, the number of characters, and the width of those characters can all vary.
You don’t need Unicode for that. It also requires you use a monospaced font.

I think the feature predates that and Unicode, though. But even then, it fails if you underline text the way it was done at the time, either by using backspace and underline characters or by using termcap (https://en.wikipedia.org/wiki/Termcap)

This makes me wonder if there's some sort of Unicode equivalent for this?
wcwidth()
Thanks, I wasn't aware of this. Here's a man page for anyone else that was interested: https://man7.org/linux/man-pages/man3/wcwidth.3.html
I'd never heard of %n, but I use printf's return value (the number of bytes written) for this kind of purpose, so

  n = printf("%s: ", prefix);
  printf("%s\n", line1);
  printf("%*s%s\n", n, " ", line2);
Yeah but the difference is that you can use %n wherever you need it in the format string. Depending on what arguments come after it figuring out the length of the printed arguments might not be trivial whereas with printf, it already has to keep a count of it during execution in order to return it at the end so it's easy to add support for it.
I seem to recall using it to auto-adjust column widths.

And we did something with it involving string translations. Since we didn't control the translated format string we couldn't just count the characters in the source code.

But it's been a really long time and I don't recall the details.

Well the fun use is using it to exploit printf format string vulnerabilities. Microcorruption has a fun level involving that IIRC.
Normally you'd use %n with input functions like scanf(), not printf().
To support format string vulnerabilities! /s