-1

I wanted to know why output is coming as 0.000000. I know printing int using float format specifier or using a type of value using b type gives unspecified behaviour as written in many place. I'm quoting it

"If a conversion specification is invalid, the behaviour is undefined. If any argument is not the correct type for the corresponding conversion specification, the behaviour is undefined."

But it is always giving 0.000000 there must be something defined going either in register or in assembly code.

In short I wanted to know what cause output to be always 0.000000 for any value of i?

#include<stdio.h>
int main()
{
    int i=10;
    printf("%f\n",i);
    return 0;
}

All said I know value of i may be somewhere in output but due to precession window size it is not shown on console. If I use %e I'm getting enter image description here

  • 1
    You want to dig into UB? Fine, do it on your box. Step through it with a debuggger, noting integer and IEEE FP format on your system, and find out exactly what is going on. I can't see that of being much use to the SO knowledge repository, though: – Martin James Jul 09 '15 at 14:06
  • 3
    I'm voting to close this question as off-topic because it seeks to have UB explained. – Martin James Jul 09 '15 at 14:07
  • This may be because the `%f` expects a floating point value *in a floating point register*, and since there is none, it displays `0.0000`. (The result of attempting to read from an uninitialized floating point register is also Undefined Behavior.) – Jongware Jul 09 '15 at 14:17
  • Use `"%e"` instead of `"%f"`. This will provide more insight. About half of all `double` print "0.000000" as the value is so small. By using `"%e"`, suspect changing to `i` will manifest themselves. – chux - Reinstate Monica Jul 09 '15 at 14:29
  • Be more careful in stating what you see. Certainly the output could be "0.000000" (6 zeros after the '.'). Why do you then state "always giving 0.0000000" ( 7 zeros after the '.') and "be always 0.00000000" ( 8 zeros after the '.')? Attention to detail is important in any problem solving. – chux - Reinstate Monica Jul 09 '15 at 14:33
  • Marking this question as duplicate is not good. What Martin James said seems to be good reason for closing this question but duplicate . – HimanshuArora9419 Jul 09 '15 at 14:40
  • The short answer is that the bit pattern in `i` is being *interpreted* as a 64-bit double, and given common floating point representations will wind up corresponding to something in the neighborhood of `2^-47`, which is 0 out to something like 13 or 14 decimal places (assuming you're on x86, anway). – John Bode Jul 09 '15 at 15:37
  • However, I must also point out that in general it's a waste of time to figure out *why* you get a particular result for undefined behavior, since the result isn't guaranteed to be repeatable. The main lesson to take away from this is "don't do that". – John Bode Jul 09 '15 at 15:39
  • Parameters passing, on the stack, via registers, etc. is not specified by C. Certainly code attempts to pass an `int` (likely 32-bit) and `printf()` looks for a `double` (likely 64-bit). Likely the sizes are mis-match. Given output `"6.952880e-308"` which could have the hex pattern of `0028FF8FE2FFCBFD` and looks nothing like `i = 0x0000000A`, I suspect a mis-match in how the data was passed contributed to the unusual result too. To _know_, you could start dumping the assembly code and analyzing it to determine what undefined behavior occurred - but that is _work_ and of questionable value. – chux - Reinstate Monica Jul 09 '15 at 20:56

6 Answers6

1

You may get same results for a day and another result on next day, that is the all story about undefined behavior. Standard don't guarantee any deterministic result for undefined behavior.

You should use proper type specifiers while printing using printf

Steephen
  • 14,645
  • 7
  • 40
  • 47
1

Undefined behaviour doesn't mean that you have to obtain different results in different runs. It only means that you must not expect any well-defined behaviour.

dlask
  • 8,776
  • 1
  • 26
  • 30
1

Use
printf("%f\n",(float)i);

The compiler do not automatically cast your int to float

Edit: I think this is an interesting question, so I found a similar article: Code for printf function in C

Then I tried to explore __printf , vfprintf and ___printf_fp

__printf (const char *format, ...)
{
   va_list arg;
   int done;

   va_start (arg, format);
   done = vfprintf (stdout, format, arg);
   va_end (arg);

   return done;
}

In vfprintf, they define a jump_table, that processes the specific format (%d, %f, %x ...)

static const uint8_t jump_table[] =
 {
   /* ' ' */  1,            0,            0, /* '#' */  4,
              0, /* '%' */ 14,            0, /* '\''*/  6,
              0,            0, /* '*' */  7, /* '+' */  2,
              0, /* '-' */  3, /* '.' */  9,            0,
   /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
   /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
   /* '8' */  8, /* '9' */  8,            0,            0,
              0,            0,            0,            0,
              0, /* 'A' */ 26,            0, /* 'C' */ 25,
              0, /* 'E' */ 19, /* F */   19, /* 'G' */ 19,
              0, /* 'I' */ 29,            0,            0,
   /* 'L' */ 12,            0,            0,            0,
              0,            0,            0, /* 'S' */ 21,
              0,            0,            0,            0,
   /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
              0,            0,            0,            0,
              0, /* 'a' */ 26,            0, /* 'c' */ 20,
   /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
   /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28,            0,
   /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
   /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
   /* 't' */ 27, /* 'u' */ 16,            0,            0,
   /* 'x' */ 18,            0, /* 'z' */ 13
 };

Then they put LABEL in this vfprintf function (something like switch case)

int vfprintf (FILE *s, const CHAR_T *format, va_list ap)
{
...
LABEL (form_percent):           
  /* Write a literal "%".  */   
  outchar (L_('%'));            
  break;                        

LABEL (form_integer):           
  /* Signed decimal integer.  */
  base = 10;

LABEL (form_float): 
...
}

In Label form_float, they define a struct which defined float format

struct printf_info info = { 
.prec = prec,                    
.width = width,                  
.spec = spec,                    
.is_long_double = is_long_double,
.is_short = is_short,            
.is_long = is_long,              
.alt = alt,                      
.space = space,                  
.left = left,                    
.showsign = showsign,            
.group = group,                  
.pad = pad,                      
.extra = 0,                      
.i18n = use_outdigits,           
.wide = sizeof (CHAR_T) != 1 
}; 

Finally, they call

int ___printf_fp (FILE *fp, 
                  const struct printf_info *info,
                  const void *const *args)

to print the output.

Conclusion: if input format is not correct, we wil have a wrong format struct info, then output must be wrong too.

Community
  • 1
  • 1
Ngo Thanh Nhan
  • 503
  • 2
  • 5
  • 17
0

You are pushing integer into stack, but telling printf that it is floating point.

Here is a correct example:

#include<stdio.h>
int main()
{
  int i=10;
  printf("%f\n", (float)i);
  return 0;
}

Addition:

There is a difference of representation of int and float when passing as varargs. In most ABIs, float is passed as double, so it is twice as long than int (assuming int size 4 and double 8). So you can experiment with int64_t data type instead. In this case, you can see different values if you fit binary presentation of some floating point value into integer.

Valeri Atamaniouk
  • 5,125
  • 2
  • 16
  • 18
0

In short I wanted to know what cause output tu be always 0.00000000 for any value of i?

In short, by writing

  printf("%f\n",i);

i.e., printing an int using %f is undefined behaviour. Output can be anything, even your phone number or ATM PIN, also.

To quote the standard, (which you already know), with emphasis from my side

If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

The printf function uses the format specifiers to figure out what to pop off the stack. So when it sees %f, interprets them as double.

As here in your code types are not compatible (as promoted according to the default argument promotions) behaviour is undefined.

ameyCU
  • 16,489
  • 2
  • 26
  • 41