2

I'm trying to use a variable to set a somewhat dynamic field width in a printf() format specifier. I searched the site and found the following which seemed to be just the help that I need.

Set variable text column width in printf

When I use "%*1$d%*2$s" I get the following error.

ex8_3.c:29:11: warning: missing $ operand number in format [-Wformat=]
   29 |    printf("The value entered, in characters, was \"%*1$d%*2$s\".\n", fieldWidth, string);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

However, when I use "%1$*d%2$*s" I get the following error.

ex8_3.c: In function ‘main’:
ex8_3.c:29:4: warning: missing $ operand number in format [-Wformat=]
   29 |    printf("The value entered, in characters, was \"%1$*d%2$*s\".\n", fieldWidth, string);
      |    ^~~~~~

Note the different locations of the asterisks in both statements. The second version seems to be the "more correct" one, according to the compiler. What I don't understand, in both cases, is the "missing $ operand number" referred to in the error messages. The printf() uses two variables and I have provided two instances of "$ operand number". Given the examples in the web page linked to above, I just don't see what I am doing wrong/not understanding. Could someone please explain what the error messages are referring to and what corrections I need to implement ?

Here is the code in question.

int main(void)
{
   int number = 0;                                 // Value supplied by user.
   int arraySize;                                  // Size of the digit array.
   int fieldWidth = 0;                             // Allow variable field width in printf().
   
   number = readValue();                           // Read in value from user.
   arraySize = countDigits(number) + 2;            // Get array size.
   fieldWidth = arraySize + 2;                     // Set variable field width for printf().
   
   char string[arraySize];                         // Define array to hold digit characters.
   itoa(number, string);                           // Convert value to string.
   printf("The value entered, in characters, was \"%1$*d%2$*s\".\n", fieldWidth, string);
   return 0;
}

Here is the command line in use.

gcc ex8_3.c -Wall -std=c11 -ggdb -o ex8_3
Stuart
  • 121
  • 7
  • 4
    Notice in the answer you linked to that there's only one `%` but you have two. Also, what is `1$` and `2$` supposed to do? Doesn't `printf("The value entered, in characters, was \"%*s\".\n", fieldWidth, string);` work? – Ted Lyngmo Aug 02 '23 at 13:19
  • @Ted Lyngmo: Thanks for such a swift reply. I took out the second ```%``` and still got the exact same error message. – Stuart Aug 02 '23 at 13:30
  • 1
    Do you want to use POSIX positional printf arguments _or_ you want to specify width of the field? Just `%*s`, remove all the `$`. `Set variable text column width in printf` So why not use the `printf("%*d", width, value);` answer? – KamilCuk Aug 02 '23 at 13:31
  • @KamilCuk: The idea was to use a variable to specify a dynamic field width that would change depending on the number of digits entered by the user. I had not heard of POSIX positional arguments before. I was just trying [and failing] to implement what I saw in the web page linked to in my original posting. Still very much learning here. – Stuart Aug 02 '23 at 13:36
  • 1
    @KamilCuk: Thanks, the format specifier ```\"%*s\"``` has allowed a clean compilation. Now to correct the logic. :-) – Stuart Aug 02 '23 at 13:44
  • @Stuart `%*s` is what I proposed right there in the first comment. I also provided an answer making it work with POSIX positional arguments. – Ted Lyngmo Aug 02 '23 at 13:49
  • @Ted Lyngmo: According to the web page that I linked to, the printf() using two variables [one for the field width and one for the data value to be displayed] should use two n$ arguments in the format specifier yet, as I mentioned in my previous answer, ```\"%*s\"``` seems(!) to have allowed a clean compilation. The program seems to be just giving the wrong output value. This just might be due to a missing n$ argument in the format specifier. I am just about to investigate that. – Stuart Aug 02 '23 at 13:53
  • @Stuart Where on the page you linked to does it say that one should use two `n$` arguments in the format specifier? It seems one answer mentions POSIX positional arguments for completeness only, but does it wrong afaik. And yes, `%*s` as I proposed both in my comment and in the answer is the common way to do it and it's also portable in that it doesn't require POSIX extensions. It doesn't just seem to work, it works. – Ted Lyngmo Aug 02 '23 at 14:15
  • _"The program seems to be just giving the wrong output value."_ - To be able to help with that, I would need to see a [mre]. Is `fieldWidth` an `int` etc.? – Ted Lyngmo Aug 02 '23 at 14:24
  • @Ted Lyngmo: I included the main() function at the bottom of my original posting. There you will see that ```fieldWidth``` is indeed declared as an ```int```. – Stuart Aug 02 '23 at 14:44
  • No worries. :-) What's wrong with ouput if you use one of the format strings I suggested? – Ted Lyngmo Aug 02 '23 at 14:46
  • @TedLyngmo: Currently using format specifier ```\"%2$*1$s\"```. When I enter, for example, 5678, the output is ```The value entered, in characters, was " 112334".```. This is wrong in that the digit chars are wrong in number as well as there values. There should be only as many digit chars as digits originally entered. The digit chars are held in an array of char. – Stuart Aug 02 '23 at 15:04
  • @Stuart I see. That's not a problem with the format specifier though. You'd get the "wrong" output if you just did `puts(string);` because that's what put in `string`. If you do `printf("%d\n", readValue);` does it print `5678`? If you do `printf("%d\n", arraySize);` does it print `6`? – Ted Lyngmo Aug 02 '23 at 16:31
  • 1
    @Ted Lyngmo: All sorted! Thanks for your two final suggestions. They pointed me in the right direction. In my ```readValue()``` function I had the line ```value = (character + '0') + (value * 10);```. You have no doubt already spotted that the first parens should have used '-' and not '+'. Thanks again for all(!!) your help. – Stuart Aug 03 '23 at 13:58
  • @Stuart You're welcome! I'm very glad to hear that it helped! – Ted Lyngmo Aug 03 '23 at 15:28

1 Answers1

3

It looks like you are trying to use the POSIX positional arguments using %n$ (field to be printed) and *m$ (width). The width modifier here needs to be supplied after the number selecting which argument to print:

printf("... was \"%2$*1$s\".\n", fieldWidth, string);
  • %2$ - The argument to be printed, string
  • *1$ - The argument holding the width, fieldWidth
  • s - and the field is a string

You'd get the same output with the much simpler:

printf("... was \"%*s\".\n", fieldWidth, string);
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108