the stack's role with format strings - c

Okay this is going to be somewhat lengthy.
So I've got a program that uses two %n format parameters in it's a printf() statement. %n essentially writes data without displaying anything... So when my format function encounters %n parameter, it writes the number of bites that have been written by the function to the address of the corresponding function argument.
#include <stdio.h>
#include <stdlib.h>
int main() {
int A = 5, B = 7, count_one, count_two;
printf("The number of bytes written up to this point X%n is being stored in
count_one, and the number of bytes up to here X%n is being stored in
count_two.\n", &count_one, &count_two);
printf("count_one: %d\n", count_one);
printf("count_two: %d\n", count_two);
printf("A is %d and is at %08x. B is %x.\n", A, &A, B);
exit(0);
}
the output of the program is:
The number of bytes written up to this point X is being stored in count_one,and the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at bffff7f4. B is 7.
With regards to this printf
printf("A is %d and is at %08x. B is %x.\n", A, &A, B);
Now, the arguments are pushes to the stack in reverse order first the value of B then the value address of A then the value address of A, and finally the address of the format string...
Now if only two arguments are pushed to the stack with a format string that uses three format parameters?
So I removed the last argument in the code above to match this printf() argument
printf("A is %d and is at %08x. B is %x.\n", A, &A);
and what happens when I compile and execute is...
The number of bytes written up to this point X is being stored in count_one, and the number of
bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at bffffc24. B is b7fd6ff4
So I get this b7fd6ff4, what is that? What does this mean with relations to the stack frame for the format function?
Any insight or explanation would be much appreciated.

Having either the wrong number of format specifiers or mismatched format specifiers invokes undefined behavior.
From section 7.21.6.1 of the C standard regarding the fprintf function:
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.
What this means is that you can't make any reliable prediction about what value the function will receive if you don't pass it enough parameters. What will most likely happen in an implementation that uses a stack and has optimizations disabled is that it will grab whatever value happens to be next in memory next to the last parameter pushed onto the stack.

the following proposed code:
fixes the problems listed in the comments to the question
cleanly compiles
performs the desired functionality
and now the proposed code:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int A = 5;
int B = 7;
int count_one;
int count_two;
printf("The number of bytes written up to this point X%n is being stored"
" in count_one, and the number of bytes up to here X%n is being"
" stored in count_two.\n",
&count_one,
&count_two);
printf("count_one: %d\n", count_one);
printf("count_two: %d\n", count_two);
printf("A is %d and is at %p. B is %x.\n", A, (void*)&A, B);
exit(0);
}
a typical run of the program results in:
The number of bytes written up to this point X is being stored in count_one, and the number of bytes up to here X is being stored in count_two.
count_one: 46
count_two: 113
A is 5 and is at 0x7fff19c28ea8. B is 7.

Under the 32-bit x86 calling convention all function parameters are passed on the stack. If you call printf() with more format specifiers than arguments the function will gladly keep walking up the stack and grabbing whatever values are there to find something to display.
The specific contents of the stack are going to be variable- usually function-local variables, function return pointers, or stack pointers.

printf assumes that you pushed all 4 arguments on the stack. It is expecting B to be on the stack regardless of whether you provided it or not. If you did not provide it then it will use whatever is in that memory location and print it.

Related

why array shows garbage value when only one format specifier used?

i am trying to print value of an array in C-language.I am using 3 format specifier for only one value of array , my problem is that i don't understand that how other two values are coming in my output .
here is my code:
int arr[6] = {3,4,42,2,77,8};
printf("%d %d %d ",arr[2]);
output :
42 3 4
According to the C Standard
If there are insufficient arguments for the format, the behavior is
undefined.
In your call of printf
printf("%d %d %d ",arr[2]);
the arguments are exhausted after the first format specjfjer. So the function call has undefined behaviour and the output can contain any garbage.
You shall write
printf( "%d ", arr[2] );
or for example
printf( "%d %d %d ", arr[2], arr[3], arr[4] );
When printf() sees three format specifiers, it looks at specific locations, either in stack memory or in CPU registers, depending on the conventions of the compiler, for three arguments.
You provided one, but some data that you have no control over exists in the other two locations, and that's what gets printed.
The other two values are garbage and don't have any meaning. The function printf requires as many arguments as there are format specifiers, so in your case three. Since you only provided one argument (arr[2]), the other two specifier 'don't know' what to print - thus gargabe will come out. Make sure to provide the required number of arguments.
If you want to print the array number by number, you will have to use a for loop.
The signature of printf is.
int printf(char*, ...);
So, you can have a variable number of arguments, then.
printf("%d %d %d ",arr[2]);
Is a valid call of the function printf.
However, because you provided no values ​​yourself, then you will get whatever... that in your special case it seems that it printed arr[0] and arr[1].

i try this piece of code in all possible way ,but i cant find why?

Here is the program in C and its output
#include <stdio.h>
#include <conio.h>
void main()
{
int i, t[4], s[4];
for(i=0;i<=3;i++)
{
printf("\n%d",&s[i]);
printf(" %d",&t[i]);
}
for(i=0;i<=3;i++)
{
printf("\n%d %d",&s[i],&t[i]);
}
}
output:
8600 8608
8602 8610
8604 8612
8606 8614
8600 8641
8602 8641
8604 8641
8606 8641
I want to know what exactly happened in second for loop statement that making different from first for loop.
The only obvious problem in your program is that you are passing pointer arguments corresponding to printf's %d format. This is undefined behavior. It can happen to work for some compilation platforms, but you shouldn't count on it.
The most likely explanation is that the ABI for passing pointer arguments to a variadic functions such as printf is, on your platform, different from the ABI for passing int arguments. For all we know, on your platform, pointers are not even the same width as int.
Use the %p format to print a pointer. Or better, use printf("%p", (void*)…);, which is even more portable, in case not all pointer types have the same representation.
The problem is that you are using the wrong format code for printing a pointer. As #PascalCuoq says, you should use %p, not %d.
The reason is that pointers and integers are clearly not the same size, on your system.
When you pass the two pointers to different printf calls %d will print the first part of the pointer value.
When you pass the two pointers to the same printf call, getting the lengths wrong will mean that it will print two different values that do not line up with either pointer.
Your printf statements are printing an integer, put you're putting a pointer (&t[i] means address of the i th element of the t array).
An integer and a pointer are not necessarily the same number of bytes and most implementations of printf takes a fixed number of bytes from the stack for each % field. Also the 'endianism' of the machine will determine whether the least or most significant bit of the address are used as in integer when printf takes its field data from the stack. It looks like you are running on a 16 bit machine with 24 bit addresses and LSB ordering - some kind of micro-controller, I'd guess.
Your arrays are at the memory addresses (converted to hex from your output:
s : 0xC12198
t : 0xC121A0
(24 bit addreses, I think.)
The first loop handles each array seperately in diffierent printf statements, hence you can see the least significant bits of each array incrementing with each iteration.
The second loop tries to handle both arrays in one `printf. So you get values indicating the incrementing part of one of the addresses, plus the second is the most significant part of the address, which is not incrementing, and the second array's address is not output at all.

Why does the strange value come out with an unnecessary % conversion in the code in C language?

I started learning programming only few days ago, so basically I have no knowledge.
I'm starting with C, and I wrote a very simple code which is:
int main (int argc, const char * argv[])
{
printf("%d + %d", 1 + 3);
return 0;
}
with the code above, I got the value of 4 + 1606416608 and later found that the return value is wrong because I put more %d than necessary. Then my question is, how did that strange value actually come out? If anyone knows, please help me. Thank you!!
You know what you did wrong already, so to explain what your particular implementation of C probably did:
When you call printf, a new stack frame is pushed to the call stack. The call stack is a last in first out structure with one 'frame' per called function. So if main called logStuff which called printf then three consecutive frames would be for main, then logStuff, then printf. When printf returns, it's frame is removed from the structure and execution continues with logStuff.
So a frame usually contains at least the parameters passed to the function and storage for local variables. Those things may be one and the same, it's implementation dependant.
With a variadic function like printf there's a stream of unnamed parameters. The bit patterns will be put into an appropriate place in the frame. But C is not a reflective language. Each bit patten doesn't inherently have a meaning: any one could be an integer, a float, or anything else. It also isn't a language that invests in bounds checking. You're trusted to write code that acts correctly.
printf determines the types and number of unnamed parameters from the string. So if you've given it false information, it will interpret the bit patterns with something other than their correct meaning and it may think there are fewer or more than are really there.
You told it there were more. So what probably happened was that the parameters were in the equivalent of an array and it read a value from beyond the end of the array. As it's all implementation dependent, that value may have been meant to represent anything. It could be the address of the caller. It could be uninitialised storage for another local variable. It could be bookkeeping. It could be the format string, incorrectly interpreted as an integer.
What it isn't is any reliable value. It may not even always be safe to read.
You are in undefined behavior land... you are telling a variadic function that you have 2 int sized params, then you only supply one, you are leaking something from the stack.
1) %d is a format specifier, it tells the compiler how you want to access the value stored at a particular location.(here as an integer)
2) For every format specifier you need to provide a corresponding variable or a value, otherwise at runtime you will get "garbage" i.e. some random value.
Example :
int main()
{
int a = 65;
printf("\na = %d", a); // here the value stored in a is accessed as an integer.
printf("\na = %c", a); // the value inside a is accessed as a character.
return 0;
}
In the above example '%d' in the first printf statement tells the compiler that the value stored in the variable a is to be accessed as an integer. (o/p - 65)
In the second printf statement '%c' is used to access the same variable as a character.(o/p - A)
Your code expects two numerical parameters to be printed, and you're giving it one.
Expected:
printf("%d + %d", <some_num>, <another_num>);
You're giving it:
printf("%d + %d", <some_num>);
Where <some_num> is what 1+3 evaluates to. The function expects another argument, but receives garbage instead.
What you should do is
printf("%d + %d = %d", 1, 3, 1+3);

C variable assignment issue

I think the title does not suit well for my question. (I appreciate it, if someone suggests an Edit)
I am learning C with "Learn C The Hard Way.". I am using printf to output values using format specifiers. This is my code snippet:
#include <stdio.h>
int main()
{
int x = 10;
float y = 4.5;
char c = 'c';
printf("x=%d\n", x);
printf("y=%f\n", y);
printf("c=%c\n", c);
return 0;
}
This works as I expect it to. I wanted to test it's behavior when it comes to conversion. So everything was ok unless I made it to break by converting char to float by this line:
printf("c=%f\n", c);
Ok, I'm compiling it and this is the output:
~$ cc ex2.c -o ex2
ex2.c: In function ‘main’:
ex2.c:13:3: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
printf("c=%f\n", c);
^
The error clearly tells me that It cannot convert from int to float, But this does not prevent the compiler from making an object file, and the confusing part is here, where I run the object file:
~$ ./ex2
x=10
y=4.500000
c=c
c=4.500000
As you can see printf prints the last float value it printed before. I tested it with other values for y and in each case it prints the value of y for c. Why this happen?
Your compiler is warning you about the undefined behaviour you have. Anything can happen. Anything from seeming to work to nasal demons. A good reference on the subject is What Every C Programmer Should Know About Undefined Behavior.
Normally, int can convert to double just fine:
int i = 10;
double d = i; //works fine
printf is a special kind of function. Since it can take any number of arguments, the types have to match exactly. When given a char, it is promoted to int when passed in. printf, however, uses the %f you gave it to get a double. That's not going to work.
Here is how one would implement their own variadic function, taken from here:
int add_nums(int count, ...)
{
int result = 0;
va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
result += va_arg(args, int);
}
va_end(args);
return result;
}
count is the number of arguments that follow. There is no way for the function to know this without being told. printf can deduce it from the format specifiers in the string.
The other relevant part is the loop. It will execute count times. Each time, it uses va_arg to get the next argument. Notice how it gives va_arg the type. This type is assumed. The function needs to rely on the caller to pass in something that gets promoted to int in order for the va_arg call to work properly.
In the case of printf, it has a defined list of format specifiers that each tell it which type to use. %d is int. %f is double. %c is also int because char is promoted to int, but printf then needs to represent that integer as a character when forming output.
Thus, any function that takes variadic arguments needs some caller cooperation. Another thing that could go wrong is giving printf too many format specifiers. It will blindly go and get the next argument, but there are no more arguments. Uh-oh.
If all of this isn't enough, the standard explicitly says for fprintf (which it defines printf in terms of) in C11 (N1570) §7.21.6.1/9:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
All in all, thank your compiler for warning you when you are not cooperating with printf. It can save you from some pretty bad results.
Since printf is a varargs function, parameters cannot be converted automatically to the type expected by the function. When varargs functions are called, parameters undergo certain standard conversions, but these will not convert between different fundamental types, such as between integer and float. It's the programmer's responsibility to ensure that the type of each argument to printf is appropriate for the corresponding format specifier. Some compilers will warn about mismatches because they do extra checking for printf, but the language doesn't allow them to convert the type -- printf is just a library function, calls to it must follow the same rules as any other function.
Here is a very general description, which may be slightly different depending on the compiler in use...
When printf("...",a,b,c) is invoked:
The address of the string "..." is pushed into the stack.
The values of each of the variables a, b, c are pushed into the stack:
Integer values shorter than 4 bytes are expanded to 4 bytes when pushed into the stack.
Floating-point values shorter than 8 bytes are expanded to 8 bytes when pushed into the stack.
The Program Counter (or as some call it - Instruction Pointer) jumps to the address of function printf in memory, and execution continues from there.
For every % character in the string pointed by the first argument passed to function printf, the function loads the corresponding argument from the stack, and then - based on the type specified after the % character - computes the data to be printed.
When printf("%f",c) is invoked:
The address of the string "%f" is pushed into the stack.
The value of the variable c is expanded to 4 bytes and pushed into the stack.
The Program Counter (or as some call it - Instruction Pointer) jumps to the address of function printf in memory, and execution continues from there.
Function printf sees %f in the string pointed by the first argument, and loads 8 bytes of data from the stack. As you can probably understand, this yields "junk data" in the good scenario and a memory access violation in the bad scenario.

String #define returns a random integer

As far as I know #define is just a string replacement and it's not a variable, so it doesn't have any memory address or something.
Suppose this code:
#include <stdio.h>
#define ONE "a"
main() {
printf("the number is: %d\n", ONE);
}
Then when I compile and run this program, I get a random string each time:
the number is: 8179551
the number is: 21127007
the number is: 57114463
...
If the #define doesn't have any memory address, then what's this value and why it's changed every time?
In your code
printf("the number is: %d\n", ONE);
is equivalent to
printf("the number is: %d\n", "a");
In fact you are printing the address of the string "a" as a decimal.
And you are getting random value in each execution that's because the address of "a" is got random address in each execution
The string "a" is a literal string and it's stored in the read only memory. The printf is printing the address of this memory
MOHAMED is right, you printing the adress of a string
what you what to do this
#define ONE 'a'
everything between two ''s are characters, only one character is allowed
This program invokes undefined behavior because the format specification doesn't match the type of argument (int versus char *).
C99, 7.19.6.1 # 9 (fprintf)
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.
The correct way to print an address is with %p and via a (void *) argument:
printf("the address is: %p\n", (void *)ONE);

Resources