Search code examples
cprintfformat-specifiers

different printf behavior with float * and int *?


First, let me clarify that I know passing pointers as arguments to these printf specifiers is not correct. I am interested however in knowing what is going on in printf when it is done.

Using the normal print specifiers, %d for int, and %f for float, why is it the int * prints, while the float * will not?

For example, given these variables (unitialized):

int a, *pA;
float b, *pB;

pA = &a;  
pB = &b;

When called like this:

void printVar(int *a, float *b)
{
    printf("%d\n", a);//why does "a" print at all?
    printf("%d  %p\n",   a,  b);// when "b" prints only using %p
    //printf("%d  %f", a,  b);// but fails on parameter mismatch using %f
    printf("%d  %f\n"  ,  *a, *b);// prints normally (as expected)
}

Why do I get this?: ("a" prints OK, but "b" prints only with %p or by passing *b)

enter image description here

[edit] entire code to clarify and address some of the comment questions:

#include <ansi_c.h>

void printVar(int *a, float *b)
{
    printf("%d\n", a);//why does "a" print at all?
    printf("%d  %p\n",   a,  b);// when "b" prints only using %p
    //printf("%d  %f", a,  b);// but fails on parameter mismatch using %f
    printf("%d  %f\n"  ,  *a, *b);// prints normally (as expected)
}

int main()
{
    int a, *pA;
    float b, *pB;
    char s[100], *pS;

    pA = &a;
    pB = &b;
    pS = &s[0];

    printVar(pA, pB);

    getchar();

    return 0;
}

***[edit 2] addressing some comments about actual content if uncomment 3rd printf

I get the following two run-time notices, then get no output for the printf in line 3:
enter image description here
enter image description here


Solution

  • You have these parameters:

    int *a, float *b
    

    This:

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

    most likely treats the memory space occupied by a (which is of type int*) as if it were an object of type int. On many systems, that will give you an almost meaningful result. (Of course if you really want to print a pointer value, you need to cast it to void* and use %p, but you're asking about the behavior of your incorrect code, not how to fix it.)

    Things can get strange if int and int* are not the same size, or if ints and pointers are passed differently as arguments (some CPUs have had dedicated address and/or floating-point registers, for example).

    printf("%d  %p\n",   a,  b);
    

    It's very likely that void* and float* have the same representation, though that's not guaranteed by the language. If int and int* happen to be the same size, and are passed using the same argument-passing convention, this will most likely print the contents of the pointer a as if it were an int object, and then print the value of b as a pointer.

    //printf("%d  %f", a,  b);// but fails on parameter mismatch using %f
    

    "%f" requires an argument of type double, not of type float (float arguments are promoted to double for variadic functions like printf). If int and int* are the same size, and double and float* are the same size, and all these types are passed using the same argument-passing convention, then this will most likely print the value of the pointer object a as if it were an int, and the value of the pointer object b as if it were a double object. The latter is likely to give you floating-point value that's completely garbage, perhaps even a NaN or Infinity. But if any of these assumptions fail, printf will likely grab data off the stack (or from registers) in some order that may or may not match up with the argument values.

    Every one of the above printf calls has undefined behavior, which means that, strictly speaking, you should have no expectations about what will happen -- even that the behavior is in any way consistent. Understanding what's going on under the covers can be useful in recognizing the cause of an error (ah, that garbage floating-point value looks similar to what I got when I messed up a format string last month), but not really for anything else.

    printf("%d  %f\n"  ,  *a, *b);// prints normally (as expected)
    

    Ah, that's more like it -- but if this is executed after the previous calls, their undefined behavior may mess things up so badly that even this doesn't work. Also, looking at your entire program, the variables a and b in main (whose addresses are passed to printVar) are not initialized, so even in the best case *a and *b are garbage. Thanks to haccks for pointing this out in a comment.