Result of Printf ("%d", &a) - c

I have a code in C .
int a;
a =10;
printf ("%d", &a);
I want to know if some garbage will be printed or error msg will be shown.
Basically I am interested in knowing how printf works. Does it have a list of variables in a table sort of things. If a table is there from where it will take the value of &a

This is a beginners question and deserves to be answered properly. (I'm startled by the downvotes and the non-constructive comments)
Let me give a walk-throu line by line:
int a;
The first line declares a variable with the name a. The variable is of type integer and with normal compilers (Microsoft Visual C++ on Windows, GCC on linux, Clang on Mac) this usually 32 bits wide. The integer variable is signed because you did not specify unsigned. This means it can represent values ranging from –2,147,483,648 to 2,147,483,647.
a =10;
The second line assigns the value 10 to that variable
printf ("%d", &a);
The third line is where you get the surprising result. "%d" is the "format string" it defines how the variables, given as further arguments are formatted and subsequently printed. The format string comprises of normal text (which will be printed normally) and control-sequences. the control sequences start with the character % and end with a letter. The letter specifies the argument type that is expected. d in the above case expects a integer value.
The problem with your code is that you do not specify an itenger value, you give the address of an integer value (with the address-of & operator). The correct statement would be:
printf ("%d", a);
Simple.
I recommend that you have a read on a good C book. I recommend "The C programming language" which is from the original authors of the language. You find this book on amazon, but you find it also online.
You can find the same answers reading in the standard. But to be honest, these documents are not easy reading. You can find a draft of the C11 standard here. The description of the formatting options starts on page 309. (drafts are usually good enough for programming purposes, and are usually available for free).

This is undefined behaviour.
If you are new to C, this may be a surprise. However the C specification defines the behaviour of certain programs (called "correct programs"). If you do not follow the rules in the specification, then your program is not correct, and literally anything may happen. The above link goes into more detail.
Your program doesn't follow the rules because the %d format specifier for printf must have a corresponding argument of type int (after the default argument promotions), but instead you pass an argument of type int *.
Since it is undefined behaviour, the output is meaningless and it is generally not worthwhile to investigate.

It will print the address of the variable 'a'. Remember that the & operator returns the address of the operand.

Related

printf with unmatched format and parameters

i'm trying to understand the printf function.
I know after i read about this function that the c compiler automatically casts all the parameters which are smaller than int like chars and shorts to int.
I also know that long long int (8 bytes) is not casted and pushed to the stack as it is.
so i wrote this simple c code:
#include <stdio.h>
int main()
{
long long int a = 0x4444444443434343LL;
// note that 0x44444444 is 4 times 0x44 which is D in ascii.
// and 0x43434343 is 4 times 0x43 which is C in ascii.
printf("%c %c\n", a);
return 0;
}
that creates the a variable whose size is 8 bytes and pushes it to the stack.
i also know that the printf loops through the format string and when it sees %c it will increment the pointer by 4 (because it knows that a char was converted to int - example below)
something like:
char c = (char) va_arg(list, int) -->
(*(int *)((pointer += sizeof(int)) - sizeof(int)))
as you can see it gets the 4 bytes when the pointer points, and increment it by 4
My question is:
in my logic, it should print on little endian machines C D
this is not what happens and i ask why? im sure some of you know more than me about the implementation and thats why i ask his question.
EDIT: the actual result is C with some garbage character follows it.
i know some might say that its undefined behavior - it really depends on the implementation and i just want to know the logic of the implementation..
Your logic would have explained the behavior of early C compilers in the 70s and 80s. Newer ABIs use a variety of methods to pass arguments to functions, including variable argument functions. You have to study your system ABI to understand how parameters are passed in your case, inferring from constructions that have explicit undefined behavior does not help.
By the way, types shorter than int are not cast or casted, they are promoted to int. Note that float values are converted to double when passed to variable argument functions. Non integer types and integer types larger than int are passed according to the ABI, which means they may be passed in regular registers or even special registers, not necessarily on the stack.
printf relies on macros defined in <stdarg.h> to hide these implementation details, and thus can be written in a portable manner for architectures with different ABIs and different standard type sizes.
There is a fundamental misunderstanding here, as revealed by the comment
according to the format string here the compiler should know that 4 bytes were pushed, convert 4 bytes to char and print it...
But the problem is that there is no rule saying that C uses a single, byte-addressed stack for everything.
Different processor architectures can -- and do -- use a variety of techniques for passing arguments to functions. Some arguments may be passed on a conventional stack, but others may be passed in registers, or via other techniques. Arguments of different types may be passed in different types of registers (32 vs. 64 bit, integer vs. floating point, etc.).
Obviously a C compiler has to know how to properly pass arguments for the platform it's compiling for. Obviously a variadic function like printf has to be carefully written to fetch its variable arguments correctly, based on the platform it's being used on. But a format specifier like %d does not, repeat not, simply mean "pop 4 bytes from the stack and treat them as an int". Similarly, %c does not mean "pop 4 bytes and print the resulting integer as a character". When printf encounters the format specifier %c or %d, it needs to arrange to fetch the next argument of type int, whatever it takes to do that. And if, in fact, the next argument actually passed by the calling code was not of type int -- for example if, as here, the next argument was actually of type long long int -- there's just no way of knowing in general what might happen.
Specifically, when printf has just seen a %d or %c specifier, what it does internally is the equivalent of calling
va_arg(argp, int)
And this literally says, "fetch the next argument of type int". And then it's actually up to the author of va_arg (and the rest of the functions and macros declared in <stdarg.h>) to know exactly what it takes to fetch the next argument of type int on this particular platform.
Clearly it is possible to know what will actually happen on a particular platform. (Obviously the author of va_arg had to know!) But you won't figure it out based on the C language itself, or by making guesses about what you think ought to happen. You're going to have to read about the ABI -- the Application Binary Interface -- that specifies the details of function calling conventions on your platform. These details can be hard to find, because very few programmers actually care about them.
I said that "printf has to be carefully written to fetch its variable arguments correctly", but actually I misspoke slightly, because as I said later, "it's actually up to the author of va_arg to know exactly what it takes". You're right, it is possible to write a reasonably portable implementation of printf. There's an example in the C FAQ list.
If you want to know more about function calling conventions, another interesting topic to read about is Foreign Function Interfaces or FFI. (For example, there's another library libffi that helps you to -- portably! -- perform some more exotic tasks involved in manipulating function arguments.)
There are simply too many notes types
C specifies 11 integer types signed char, char, … unsigned long long as distinct types. Aside from char must match signed char or unsigned char, these could be implemented as 10 different encodings or just 2 (Use 64-bit signed or unsigned for all).
The standard library has a printf() specifiers for each of those 11. (Due to sub-int promotions, there are additional concerns).
So far no real issues.
Yet C has lots of other types with printf() specifiers:
ju uintmax_t
jd intmax_t
zu size_t
td ptrdiff_t
PRIdLEASTN int_leastN_t where N is 8, 16, 32, 64
PRIuLEASTN uint_leastN_t
PRIdN intN_
PRIuN uintN_t
Many others
In general1 these additional types, could be distinct from or compatible with the 11 above.
Any time code uses these other types in a printf(), the distinct/compatible issue will arise and prevent many compilers from detecting/providing the best suggested matching print specifier.
1 Various conditions/limitations exist.

Scanf is mutating my number

I have a program that grabs a user input number and adds the appropriate ending (1st, 11th, 312th, etc)
So I gave it to my friend to find bugs/ break it.
The code is
int number;
printf("\n\nNumber to end?: ");
scanf("%d",&number);
getchar();
numberEnder(number);
when 098856854345712355 was input, scanf passed 115573475 to the rest of the program.
Why? 115573475 is less than the max for an int.
INT_MAX is typically (2^31) -1 which is ~2 billion...
... if you look at 98856854345712355 & 0xffffffff you will find that it is 115573475
The C99 standard states in the fscanf section (7.19.6.2-10):
...the result of the conversion is placed in the object pointed to by
the first argument following the format argument that has not already
received a conversion result. If this object does not have an
appropriate type, or if the result of the conversion cannot be
represented in the object, the behavior is undefined [emphasis added].
This is true in C11 as well, though fscanf is in a different section (7.21.6.2-10).
You can read more about undefined behavior in this excellent answer, but it basically means the standard doesn't require anything of the implementation. Following from that, you shouldn't rely on the fact that today scanf uses the lower bits of the number because tomorrow it could use the high bits, INT_MAX, or anything else.
098856854345712355 is too big of a number for int.
long long number;
printf("\n\nNumber to end?: ");
scanf("%lld",&number);
getchar();
numberEnder(number);
The answer to why you get a specific garbage answer is GIGO. The standard doesn't specify the result for bad input and it's implementation specific. I would hazard a guess that if you apply a 32 bit mask to the input, that's the number you would get.
Just out of curiosity, I looked up an implementation of scanf.
It boils down to
…
res = strtoq(buf, (char **)NULL, base);
…
*va_arg(ap, long *) = res;
…
Which should truncate off the high-bits in the cast. That would support the bit-mask guess, but it would only be the case for this implementation.

Automatic typecasting discrepancy

#include<stdio.h>
int main(){
float a,b;
a=5;
b=12;
printf("Result:%f",a+b);
return 0;
}
If I display the result as float,I get 17.0.No problem
But I display a+b as int,I get the result as 0.
I tried different values of a & b to look for some pattern.No matter what the values of a & b are,a+b is displayed as 0 when displayed as int.
No problems when displayed as float.
My reasoning says that if I try to print a float as an int,the decimal part will be truncated.
Where am I wrong.I searched through typecasting tutorials but couldn't interpret this discrepancy.
May be this is a very elementary doubt but I couldn't reason out the causes behind the discrepancy.I do not know if the title is appropriate.Sorry for that.
I'm a beginner.So along with the answer if you could provide a source I can refer to for such kinds of doubts,I'll be grateful & also won't bother the community with stupid doubts.
Automatic typecasting discrepancy
There is no automatic conversion of the arguments of printf() based on the format string. The arguments of printf() after the first one are promoted according to the default argument promotions, which involve promoting float to double but, to reiterate, do not take the format string into account.
No matter what the values of a & b are,a+b is displayed as 0 when displayed as int.
If you did the equivalent of printf("%d", a + b);, it is normal for it not to work, because it is not supposed to. Technically, it invokes undefined behavior. The actual effects vary depending on the compilation platform and in particular the argument-passing conventions. Printing 0 is one of the possibilities.
What would be supposed to work would be printf("%d", (int) (a + b));, which you can fully expect to print 17.

Why does %d show two different values for *b and *c in the code [b and c points to same address]

Consider the Code below
{
float a=7.999,*b,*c;
b=&a;c=b;
printf("%d-b\n%d-c\n%d-a\n",*b,*c,a);
}
OUTPUT:
-536870912-b
1075838713-c
-536870912-a
I know we are not allowed to use %d instead of %f, but why does *b and *c give two different values?
Both have the same address, can someone explain?
I want to know the logic behind it
Here is a simplified example of your ordeal:
#include <stdio.h>
int main() {
float a=7.999, b=7.999;
printf("%d-a\n%d-b\n",a,b);
}
What's happening is that a and b are converted to doubles (8 bytes each) for the call to printf (since it is variadic). Inside the printf function, the given data, 16 bytes, is printed as two 4-byte ints. So you're printing the first and second half of one of the given double's data as ints.
Try changing the printf call to this and you'll see both halves of both doubles as ints:
printf("%d-a1\n%d-a2\n%d-b1\n%d-b2\n",a,b);
I should add that as far as the standard is concerned, this is simply "undefined behavior", so the above interpretation (tested on gcc) would apply only to certain implementations.
There can be any number of reasons.
The most obvious -- your platform passes some integers in integer registers and some floating point numbers in floating point registers, causing printf to look in registers that have never been set to any particular value.
Another possibility -- the variables are different sizes. So printf is looking in data that wasn't set or was set as part of some other operation.
Because printf takes its parameters through ..., type agreement is essential to ensure the implementation of the function is even looking in the right places for its parameters.
You would have to have deep knowledge of your platform and/or dig into the generated assembly code to know for sure.
Using wrong conversion specification invokes undefined behavior. You may get either expected or unexpected value. Your program may crash, may give different result on different compiler or any unexpected behavior.
C11: 7.21.6 Formatted input/output functions:
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.
// Bad
float a=7.999,*b,*c;
b=&a;c=b;
printf("%d-b\n%d-c\n%d-a\n",*b,*c,a);
// Good
float a=7.999,*b,*c;
b=&a;c=b;
printf("%f-b\n%f-c\n%f-a\n",*b,*c,a);
Using an integer format specified "%d" instead of correctly using a float specified "%f" is what alk elliptically fails to explain as "undefined behavior".
You need to use the correct format specifier.

Puzzled about printf output

While using printf with %d as format specifier and giving a float as an argument e.g, 2.345, it prints 1546188227. So, I understand that it may be due to the conversion of single point float precision format to simple decimal format. But when we print 2.000 with the %d as format specifier, then why it prints 0 only ?
Please help.
Format specifier %d can only be used with values of type int (and compatible types). Trying to use %d with float or any other types produces undefined behavior. That's the only explanation that truly applies here. From the language point of view the output you see is essentially random. And you are not guaranteed to get any output at all.
If you are still interested in investigating the specific reason for the output you see (however little sense it makes), you'll have to perform a platform-specific investigation, because the actual behavior depends critically on various implementation details. And you are not even mentioning your platform in your post.
In any case, as a side note, note that it is impossible to pass float values as variadic arguments to variadic functions. float values in such cases are always converted to double and passed as double. So in your case it is double values you are attempting to print. Behavior is still undefined though.
Go here, enter 2.345, click "rounded". Observe 64-bit hex value: 4002C28F5C28F5C3. Observe that 1546188227 is 0x5c28f5c3.
Now repeat for 2.00. Observe that 64-bit hex value is 4000000000000000
P.S. When you say that you give a float argument, what you apparently mean is that you give a double argument.
Here what ISO/IEC 9899:1999 standard $7.19.6 states:
If a conversion specification is invalid, the behavior is undefined.239)
If any argument is not the correct type for the corresponding conversion
specification, the behavior is undefined.
If you're trying to make it print integer values, cast the floats to ints in the call:
printf("ints: %d %d", (int) 2.345, (int) 2.000);
Otherwise, use the floating point format identifier:
printf("floats: %f %f", 2.345, 2.000);
When you use printf with wrong format specifier for the corresponding argument, the result is undefined behavior. It could be anything and may differ from one implementation to another. Only correct use of format specified has defined behavior.
First a small nitpick: The literal 2.345 is actually of the type double, not float, and besides, even a float, such as the literal 2.345f, would be converted to double when used as an argument to a function that takes a variable number of arguments, such as printf.
But what happens here is that the (typically) 64 bits of the double value is sent to printf, and then it interprets (typically) 32 of those bits as an integer value. So it just happens that those bits were zero.
According to the standard, this is what is called undefined behavior: The compiler is allowed to do anything at all.

Resources