How overly-cute and/or heisenbug-laden is this method of adding commas to integers (12345 -> 12,345)?

Beginner/occasional C tinkerer here. (Reasonably comfortable with scripting languages, tend to avoid C due to its terseness, but trying to work past that.)

So, I happened to want to insert commas into some integers (a, uh… few hours ago). I got curious about various interesting (non-string-based) ways one might achieve that, found how to arithmetically reverse a string (cool), and, uh… ended up here.

I made this. I don’t know if I should keep it?

#include <stdio.h>  int fmtn(unsigned long long n, char *buf, int maxlen) {      int l = 0;     for (unsigned long long x = n; x; x /= 10, l++);      int l2 = l + (int)((l / 3.1));     if (l2 > maxlen) l2 = maxlen;     if (l > maxlen) l = maxlen;      int o = l2 - 1;     int c = l - 1;      for (; o > 0, n; c--, n /= 10) {         if (o >= 0) buf[o--] = (n % 10) + 48;         if (o >= 0 && (l - c) % 3 == 0) buf[o--] = ',';     }      buf[l2] = '';      return l2;  }  #define test(x) do { fmtn(x, b, 30); printf("\"%s\"\n", b); } while(0); #define testn(x, n) do { fmtn(x, b, n); printf("\"%s\"\n", b); } while(0);  int main(int argc, char **argv) {      char b[30];      testn(123, 1);     testn(123, 2);     testn(1234, 3);     testn(1234, 4);     testn(1234, 5);      puts("");      test(123);     test(12345);     test(123456);     test(1234567);     test(12345678);     test(123456789);     test(1234567890);     test(12345678901);     test(123456789012);     test(1234567890123);     test(12345678901234);     test(123456789012345);     test(1234567890123456);     test(12345678901234567);     test(123456789012345678);     test(1234567890123456789);     test(12345678901234567890ull);  }  

Compiling with -Wall produces this interesting message – I’m pretty sure that o will routinely <= 0:

In function 'fmtn': 15:14: warning: left-hand operand of comma expression has no effect [-Wunused-value]   for (; o > 0, n; c--, n /= 10) {               ^ 

Here’s what the supplied main outputs on my machine. The first part is a demonstration of what happens when maxlen (which doesn’t count the '') is too short (no buffer overflows! yay!):

"3" "23" "234" ",234" "1,234"  "123" "12,345" "123,456" "1,234,567" "12,345,678" "123,456,789" "1,234,567,890" "12,345,678,901" "123,456,789,012" "1,234,567,890,123" "12,345,678,901,234" "123,456,789,012,345" "1,234,567,890,123,456" "12,345,678,901,234,567" "123,456,789,012,345,678" "1,234,567,890,123,456,789" "12,345,678,901,234,567,890" 

The part I’m mostly… fascinated? with is the magic 3.1 near the top which is calculating what the length of the output string with commas added will be (the code of course works backwards). 3.1 Seems To Work™ for the values I’m supplying, but I’m 100.0% sure it’s probably secretly horribly broken on some large inputs (which I’ve not figured out how to test yet).

There are also probably a myriad of other issues I’ve not thought of in terms of coding semantics and style 🙂 (such as the fact that codegolf.SE is ← that way…)