Misused Placeholders

I received a question from a reader about improperly specifying a printf() placeholder. Specifically, he used %d (decimal integer) to output a string. Most compilers flag this condition as a warning, mismatched types or something similar. Still, the program is created and it runs. What does the output mean?

Here is the statement:

printf("%d\n",string);

Variable string is a char array. The compiler dislikes the mismatch of %d to a string (char array). The warning generated looks something like this:

warning: format specifies type 'unsigned int' but the argument has type 'char *' [-Wformat]

Still, the program builds – and runs. Here’s the full code:

2021_10_09-Lesson-a.c

#include <stdio.h>

int main()
{
    char string[] = "ABCD";

    printf("%s\n",string);
    printf("%d\n",string);

    return(0);
}

And here is the output:

ABCD
-324285993

I find the value -324285993 curious. What could it be? This question is what the reader raised: Is the numeric output the integer representation of the string? Could it be the string’s address? Some sleuthing is required.

The first change I made to the code is to replace the %d placeholder with %X for hexadecimal integer output. This way I could see if any patterns existed in the integer value, specifically if it’s a numeric representation of the string itself. Here’s the program’s output after making this change:

ABCD
E17849D7

Still no help. If the integer represents the string, it would contain hex values 41, 42, 43, and 44 for letters ABCD.

To continue to resolve the mystery, the next thing to test for is whether the integer value represents the string’s location in memory — a pointer. To confirm this guess, I added a third printf() statement to the code, as shown here:

2021_10_09-Lesson-b.c

#include <stdio.h>

int main()
{
    char string[] = "ABCD";

    printf("%s\n",string);
    printf("%X\n",string);
    printf("%p\n",string);

    return(0);
}

At Line 9, the %p placeholder outputs the address of variable string. If this value is the same as the value output with the %X placeholder, mystery solved. Here is the updated program’s output:

ABCD
E9D3E9D7
0x7ffee9d3e9d7

The third line of output isn’t identical to the second line’s value, though the last eight digits match: E9D3E9D7. The value the %d placeholder outputs is the variable’s address, but truncated to fit into an integer’s bit width.

My guess is that the %d placeholder interprets the value presented by variable string as an address, not as the string’s contents. This guess makes sense if you consider the the %s placeholder uses the string’s address to start popping out characters. Processing text isn’t the job of a %d placeholder, or even the %p placeholder. So it does the best it can, interpreting the value presented.

To get back to the reader’s question, the reason a warning is generated and not an error is that the mistake is really on behalf of the programmer. The code builds, but the output is suspect. In this example, the output is questionable in that the integer represents only a portion of the string’s address — if such output is what the programmer desired in the first place.

As I’ve repeated many times, take compiler warnings seriously. Your code may build with warnings intact, but with only a handful of exceptions, you should fix the warning and write better code.

3 thoughts on “Misused Placeholders

  1. Using the %ld placeholder yields the value 140732673640935, which is – ta da! – 0x7FFEE10549E7. Same value, an address.

    Argument *string is a single character, the ‘A’, so the %d placeholder outputs its ASCII value, 65.

    Good questions! I love exploring how C does things.

Leave a Reply