Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this printf format possible (left-justify sign and no sign on zero)?

I'm trying to use printf to get the following programmatic output:

- 20
- 15
- 10
-  5
   0
+  5
+ 10
+ 15
+ 20

The key specifications are:

  • The field width is always 4
  • The sign is always left-justified
  • The number is always right-justified
  • The zero has no sign

So far I have not been able to come up with a printf statement that will give me the desired results. The closest I have is:

for(int i = -20; i <= 20; i+=5)
{
    printf("%-+4d \n", i);
}

which produces:

-20
-15
-10
-5
+0
+5
+10
+15
+20

Is there a way to do this without having to do any cumbersome string manipulation?

like image 460
watersnake Avatar asked Jan 04 '23 10:01

watersnake


2 Answers

printf("%c%3d\n", i>0 ? '+' : i<0 ? '-' : ' ', abs(i));

Note the above fails for INT_MIN, but that shouldn't be an issue since your values are only expected to be less than 1000 in magnitude.

like image 66
ikegami Avatar answered Jan 13 '23 16:01

ikegami


A simple one-liner, not much different than others, yet with a nice look-up to a "- +" string.

printf("%c%3d\n", "- +"[i >= 0 + i > 0], abs(i));

To handle values outside the [-999 ... + 999] range and especially the pesky i = INT_MIN where the -i is undefined behavior, the code could use:

printf("%c%3u\n", "- +"[i >= 0 + i > 0], (i < 0) ? 0u - i: 0u + i);
// or
printf("%c%3lld\n", "- +"[i >= 0 + i > 0], llabs(i));

For a pedantic full range solution

// Buffer size = iceil(bit-width * log2(10)) + sign + null character
#define INT_BUF_SIZE (CHAR_BIT * sizeof(int)*31/100 + 3)

int print_int(int x) {
  char buf[INT_BUF_SIZE*2];
  sprintf(buf, "%+d", x);
  int width = 4;
  return printf("%c%*s\n", x ? buf[0] : ' ', width - 1, buf + 1);
}

Example output

- 20
   0
+ 20
+2147483647
-2147483648
like image 27
chux - Reinstate Monica Avatar answered Jan 13 '23 16:01

chux - Reinstate Monica