Does printf() depend on order of format specifiers? - c

#include<stdio.h>
main()
{
float x=2;
float y=4;
printf("\n%d\n%f",x/y,x/y);
printf("\n%f\n%d",x/y,x/y);
}
Output:
0
0.000000
0.500000
0
compiled with gcc 4.4.3
The program exited with error code 12

As noted in other answers, this is because of the mismatch between the format string and the type of the argument.
I'll guess that you're using x86 here (based on the observed results).
The arguments are passed on the stack, and x/y, although of type float, will be passed as a double to a varargs function (due to type "promotion" rules).
An int is a 32-bit value, and a double is a 64-bit value.
In both cases you are passing x/y (= 0.5) twice. The representation of this value, as a 64-bit double, is 0x3fe0000000000000. As a pair of 32-bit words, it's stored as 0x00000000 (least significant 32 bits) followed by 0x3fe00000 (most significant 32-bits). So the arguments on the stack, as seen by printf(), look like this:
0x3fe00000
0x00000000
0x3fe00000
0x00000000 <-- stack pointer
In the first of your two cases, the %d causes the first 32-bit value, 0x00000000, to be popped and printed. The %f pops the next two 32-bit values, 0x3fe00000 (least significant 32 bits of 64 bit double), followed by 0x00000000 (most significant). The resulting 64-bit value of 0x000000003fe00000, interpreted as a double, is a very small number. (If you change the %f in the format string to %g you'll see that it's almost 0, but not quite).
In the second case, the %f correctly pops the first double, and the %d pops the 0x00000000 half of the second double, so it appears to work.

When you say %d in the printf format string, you must pass an int value as the corresponding argument. Otherwise the behavior is undefined, meaning that your computer may crash or aliens might knock at your door. Similar for %f and double.

Yes. Arguments are read from the vararg list to printf in the same order that format specifiers are read.
Both printf statements are invalid because you're using a format specifier expecting a int, but you're only giving it a floatdouble.

What you are doing is undefiend behaviour. What you are seeing is coincidental; printf could write anything.
You must match the exact type when giving printf arguments. You can e.g. cast:
printf("\n%d\n%f", (int)(x/y), x/y);
printf("\n%f\n%d", x/y, (int)(x/y));

This result is not surprising, in the first %d you passed a double where an integer was expected.

http://en.wikipedia.org/wiki/Format_string_attack
Something related to my question. Supports the answer of Matthew.

Related

I'm curious about the c language printf format output value

I have a question while studying C language.
printf("%d, %f \n", 120, 125.12);
The output value in this code is:
120, 125.120000
That's it. And
printf("%d, %f \n", 120.1, 125.12);
The output value of this code is:
1717986918, 0.000000
That's it.
Of course, I understand that the output value of %d in front of us was a strange value because I put a mistake in the integer format character. But I don't know why %f is 0.000000 after that. Does the character on the back have an effect on the value of the previous character?
I'm asking because I'm curious because it keeps coming out like this even if I put in a different price.
printf is a variadic function, meaning its argument types and counts are variable. As such, they must be extracted according to their type. Extraction of a given argument is dependent on the proper extraction of the arguments that precede it. Different argument types have different sizes, alignments, etc.
If you use an incorrect format specifier for a printf argument, then it throws printf out of sync. The arguments after the one that was incorrectly extracted will not, in general, be extracted correctly.
In your example, it probably extracted only a portion of the first double argument that was passed, since it was expecting an int argument. After that it was out of sync and improperly extracted the second double argument. This is speculative though, and varies from one architecture to another. The behavior is undefined.
why %f is 0.000000 after that.
According to the C standard because %d expects an int and you passed a double, undefined behavior happens and anything is allowed to happen.
Anyway:
I used http://www.binaryconvert.com/convert_double.html to convert doubles to bits:
120.1 === 0x405E066666666666
125.12 === 0x405F47AE147AE148
I guess that your platform is x86-ish, little endian, with ILP32 data model.
The %d printf format specifier is for int and sizeof(int) is 4 bytes or 32 bits in LP64. Because the architecture is little endian and the stack too, the first 4 bytes from the stack are 0x66666666 and the decimal value of it is printed out which is 1717986918.
On the stack are left three 32-bit little endian words, let's split them 0x405E0666 0x147AE148 0x405F47AE.
The %f printf format specifier is for double and sizeof(double) on your platform is 8 or 64 bits. We already read 4 bytes from the stack, and now we read 8 bytes. Remembering about the endianess, we read 0x147AE148405E0666 that is converted to double. Again I used this site and converted the hex to a double, it resulted in 5.11013578783948654276686949883E-210. E-210 - this is a very, very small number. Because %f by default prints with 6 digits of precision, the initial 7 digits of the number are 0, so only zeros are printed. If you would use %g printf format specifier, then the number would be printed as 5.11014e-210.
This can be attributed to the fact that the printf function is not type-safe, i.e. there is no connection between the specifiers in the format string and the passed arguments.
The function converts all integer arguments to int (4 bytes) and all floats to double (8 bytes). As the types are guessed from the format string, a shift in the data occurs. It is likely that the 0.000000 appears because what is loaded corresponds to a floating-point zero (biaised exponent = 0).
Try with 1.0, 1.e34.

Why is this code printing 0?

void main()
{
clrscr();
float f = 3.3;
/* In printf() I intentionaly put %d format specifier to see
what type of output I may get */
printf("value of variable a is: %d", f);
getch();
}
In effect, %d tells printf to look in a certain place for an integer argument. But you passed a float argument, which is put in a different place. The C standard does not specify what happens when you do this. In this case, it may be there was a zero in the place printf looked for an integer argument, so it printed “0”. In other circumstances, something different may happen.
Using an invalid format specifier to printf invokes undefined behavior. This is specified in section 7.21.6.1p9 of the C standard:
If a conversion specification is invalid, the behavior is
undefined.282) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
What this means is that you can't reliably predict what the output of the program will be. For example, the same code on my system prints -1554224520 as the value.
As to what's most likely happening, the %d format specifier is looking for an int as a parameter. Assuming that an int is passed on the stack and that an int is 4 bytes long, the printf function looks at the next 4 bytes on the stack for the value given. Many implementations don't pass floating point values on the stack but in registers instead, so it instead sees whatever garbage values happen to be there. Even if a float is passed on the stack, a float and an int have very different representations, so printing the bytes of a float as an int will most likely not give you the same value.
Let's look at a different example for a moment. Suppose I write
#include <string.h>
char buf[10];
float f = 3.3;
memset(buf, 'x', f);
The third argument to memset is supposed to be an integer (actually a value of type size_t) telling memset how many characters of buf to set to 'x'. But I passed a float value instead. What happens? Well, the compiler knows that the third argument is supposed to be an integer, so it automatically performs the appropriate conversion, and the code ends up setting the first three (three point zero) characters of buf to 'x'.
(Significantly, the way the compiler knew that the third argument of memset was supposed to be an integer was based on the prototype function declaration for memset which is part of the header <string.h>.)
Now, when you called
printf("value of variable f is: %d", f);
you might think the same thing happens. You passed a float, but %d expects an int, so an automatic conversion will happen, right?
Wrong. Let me say that again: Wrong.
The perhaps surprising fact is, printf is different. printf is special. The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be, because it depends on the details of the %-specifiers buried in the format string. So there are no automatic conversions to just the right type. It's your job to make sure that the types of the arguments you actually pass are exactly right for the format specifiers. If they don't match, the compiler does not automatically perform corresponding conversions. If they don't match, what happens is that you get crazy, wrong results.
(What does the prototype function declaration for printf look like? It literally looks like this: extern int printf(const char *, ...);. Those three dots ... indicate a variable-length argument list or "varargs", they tell the compiler it can't know how many more arguments there are, or what their types are supposed to be. So the compiler performs a few basic conversions -- such as upconverting types char and short int to int, and float to double -- and leaves it at that.)
I said "The compiler can't necessarily know what the right types of the arguments passed to printf are supposed to be", but these days, good compilers go the extra mile and try to figure it out anyway, if they can. They still won't perform automatic conversions (they're not really allowed to, by the rules of the language), but they can at least warn you. For example, I tried your code under two different compilers. Both said something along the lines of warning: format specifies type 'int' but the argument has type 'float'. If your compiler isn't giving you warnings like these, I encourage you to find out if those warnings can be enabled, or consider switching to a better compiler.
Try
printf("... %f",f);
That's how you print float numbers.
Maybe you only want to print x digits of f, eg.:
printf("... %.3f" f);
That will print your float number with 3 digits after the dot.
Please read through this list:
%c - Character
%d or %i - Signed decimal integer
%e - Scientific notation (mantissa/exponent) using e character
%E - Scientific notation (mantissa/exponent) using E character
%f - Decimal floating point
%g - Uses the shorter of %e or %f
%G - Uses the shorter of %E or %f
%o - Signed octal
%s - String of characters
%u - Unsigned decimal integer
%x - Unsigned hexadecimal integer
%X - Unsigned hexadecimal integer (capital letters)
%p - Pointer address
%n - Nothing printed
The code is printing a 0, because you are using the format tag %d, which represents Signed decimal integer (http://devdocs.io).
Could you please try
void main() {
clrscr();
float f=3.3;
/* In printf() I intentionaly put %d format specifier to see what type of output I may get */
printf("value of variable a is: %f",f);
getch();
}

why i am not getting the expected output?

int main()
{
int x;
float y;
char c;
x = -4443;
y = 24.25;
c = 'M';
printf("\nThe value of integer variable x is %f", (float)x);
printf("\nThe value of float variable y is %d", y);
printf("\nThe value of character variable c is %f\n",c);
return 0;
}
Output:
The value of integer variable x is -4443.000000
The value of float variable y is 0
The value of character variable c is 24.250000
Why am I not getting the expected output?
But when I am using external casting I am getting expected output which is:
The value of integer variable x is -4443.000000
The value of float variable y is 24
The value of character variable c is 77.000000
why i am not getting the expected output ?
Short answer: Because your expectations are wrong.
You're instructing the compiler to read an integer from where y is. Which is wrong. Format specifier don't tell the compiler to do casts, just what type to expect, and trust you to provide the right type.
The behaviour can be due to the fact that, for example, a float is stored in 8 bytes. The high-order bytes will be 0 in this case. But an int is stored in 4 bytes. So you tell the compiler read the int from where y is, it reads the first 4 bytes, which are 0, and prints 0...
EDIT: As John pointed out in the comments, this is UB, which means that anything can happen:
7.21.6.1/9
If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Many computing platforms pass different types of arguments in different ways. On some platforms, floating-point arguments are passed in special floating-point registers. On most platforms, integer arguments are passed in general processor registers. Large arguments, such as structures, are stored somewhere in memory, and a pointer is passed instead (invisibly to the C source code). Once the few registers available for arguments are used, the remaining arguments are typically passed on the stack.
When you call printf, the compiler does not match the arguments you pass to the conversion specifiers in the format string. (Except that a good compiler will check and issue a warning if the types do not match.) In order to operate, the printf routine reads the format string and, when it finds a conversion specifier, it reads data from where the corresponding argument should be. If you specify “%d” but pass a float, the printf routine may read data from a general processor register, but the float value is in a floating-point register. Therefore, the value that is printed will be whatever data happened to be in the general processor register.
Similarly, when you specify “%f” but pass an integer, the printf routine may read from a floating-point register, but the integer value is in a general processor register.
The compiler will not convert printf arguments to the target type and might not warn you about the mismatches. You must match the conversion specifiers in the format string to the argument types.
Bonus: Here are documents describing how arguments are passed to subroutines on one platform (Mac OS X).
You cannot format a char as a float "%f", use "%c" or "%d" instead. I find that http://www.cplusplus.com/reference/clibrary/cstdio/printf/ is a good reference.
The format specifiers and the types of the arguments don't match, which I believe causes undefined behavior. printf doesn't do casting for you, so you have to explicitly cast the arguments.

-NaN in printf in C

I am currently experiencing issues with a Raytracer "Engine" in some calculations.
info->eyex = -1000.0;
info->eyey = 0.0;
printf("%f et %f et %f et %f et %f\n", info->eyex, info->vx, info->eyey, info->vy, info->vz);
For example, in that piece of code, values seems good, but info->eyex gives me a -nan error.
It's weird, because I reset the value before.
My psychic sense tells me that eyex is declared as an int, not as a double as it should be. When you assign -1000.0 to it, it gets truncated to the integer -1000 (your compiler should give you a warning here), which is represented in binary as 0xFFFFFC18 using two's complement notation. Likewise, assuming that eye is also an integer, its value of 0 is represented in binary as 0x00000000.
When you pass eyex, eyey, and the other parameters to printf, they get pushed on the stack so that they lie in memory with increasing addresses. So immediately before the call instruction to call the subroutine, the stack frame looks something like this:
<top of stack>
0xFFFFFC18 ; eyex
(4-8 bytes) ; vx
0x00000000 ; eyey
(4-8 bytes) ; vy
(4-8 bytes) ; vz
When printf sees the %f format specifier, that says "take 8 bytes off of the stack, interpret them as a double value, and print out that double value". So it sees the value 0xFFFFFC18xxxxxxxx, where the xxxxxxxxx is the value of info->vx. Regardless of that value, this is the IEEE 754 representation of NaN, or "not a number". It has the sign bit set, so some implementations may choose to interpret this as "negative NaN", though this has the same semantics as regular NaN.
Your compiler should also be warning you here that you're passing the wrong types of arguments to printf—it's expecting a double but you're not passing it that. GCC enables these warnings with -Wall, which I highly recommend enabling.
So, the solution is to declare eyex to be of type double (and presumably the other variables to also be double, if they're not already). Alternatively, if you don't control the definition of eyex et al (say, because they're part of a structure for a third-party library), then what you should instead be doing is printing them out with the %d modifier to print them as integers, not with %f, and you should also assign them integer values such as -1000 and 0, not floating-point values such as -1000.0 and 0.0.
Just to confirm this. I don't know exactly what triggers that behavior, though. printf is optimized at compile time, and the format string analyzed. Probably it's (wrongly) assuming something about your variable. Even though %f should work for doubles and floats, it seems it doesn't always (at least with gcc 4.4.5, which is the one I'm using)
Try assigning the value to another variable and then passing that to printf. Although ugly, that solved the problem for me.

difference between printing a memory address using %u and %d in C?

I reading a C book. To print out a memory address of a variable, sometimes the book uses:
printf("%u\n",&n);
Sometimes, the author wrote:
printf("%d\n",&n);
The result is always the same, but I do not understand the differences between the two (I know %u for unsigned).
Can anyone elaborate on this, please?
Thanks a lot.
%u treats the integer as unsigned, whereas %d treats the integer as signed. If the integer is between 0 an INT_MAX (which is 231-1 on 32-bit systems), then the output is identical for both cases.
It only makes a difference if the integer is negative (for signed inputs) or between INT_MAX+1 and UINT_MAX (e.g. between 231 and 232-1). In that case, if you use the %d specifier, you'll get a negative number, whereas if you use %u, you'll get a large positive number.
Addresses only make sense as unsigned numbers, so there's never any reason to print them out as signed numbers. Furthermore, when they are printed out, they're usually printed in hexadecimal (with the %x format specifier), not decimal.
You should really just use the %p format specifier for addresses, though—it's guaranteed to work for all valid pointers. If you're on a system with 32-bit integers but 64-bit pointers, if you attempt to print a pointer with any of %d, %u, or %x without the ll length modifier, you'll get the wrong result for that and anything else that gets printed later (because printf only read 4 of the 8 bytes of the pointer argument); if you do add the ll length modifier, then you won't be portable to 32-bit systems.
Bottom line: always use %p for printing out pointers/addresses:
printf("The address of n is: %p\n", &n);
// Output (32-bit system): "The address of n is: 0xbffff9ec"
// Output (64-bit system): "The address of n is: 0x7fff5fbff96c"
The exact output format is implementation-defined (C99 §7.19.6.1/8), but it will almost always be printed as an unsigned hexadecimal number, usually with a leading 0x.
%d and %u will print the same results when the most significant bit is not set. However, this isn't portable code at all, and is not good style. I hope your book is better than it seems from this example.
What value did you try? The difference unsigned vs. signed, just as you said you know. So what did it do and what did you expect?
Positive signed values look the same as unsigned so can I assume you used a smaller value to test? What about a negative value?
Finally, if you are trying to print the variable's address (as it appears you are), use %p instead.
All addresses are unsigned 32-bit or 64-bit depending on machine (can't write to a negative address). The use of %d isn't appropriate, but will usually work. It is recommended to use %u or %ul.
There is no such difference ,just don't get confused if u have just started learning pointers.
%u is for unsigned ones.And %d for signed ones

Resources