A sample problem asks us to consider the code below and predict what will be printed out by the function funct_1:
void func_1(int i, int j) {
printf("i is %d, j is %d\n", i, j);
}
/* ... */
/* somewhere in the code, a call to func_1 */
int i = 30;
func_1(i, i++);
/* ... */
I thought that when parameters are passed in this form where they are incremented, it is impossible to predict when the compiler would increment i. The solution, however, is:
The values in the argument are passed as an attack to the function, hence 'j' receives
a value '30' and then i receives the incremented value which is '31'.
Output: i is 31, j is 30
Could someone please explain what an attack to a function is and how this happens?
It is not impossible to predict; compilers work in a deterministic manner, even in the grey areas poorly covered or not covered by the specs. With this specific compiler arguments are pushed right to left, and the post-increment occurs shortly after the right parameter has been pushed.
The solution is wrong in general. You are correct; the behaviour of the code is undefined. On some compilers, the answer might be 30 and 31; on others, it might be 30 and 30; on others, it might be 31 and 31; and others might simply erase all the files on your hard drive (because undefined behaviour is undefined). Fortunately, the radical, remove-all-traces-of-the-trouble behaviour is relatively unlikely in a compiler.
For some specific compiler on some specific platform, the solution is probably correct.
Actually, I think that it is not possible to get 31 for j in func_1() - but an operation sequence that produces 30 and 30 is easily imaginable: the value of i is pushed twice, then I is incremented, then the function is called.
Related
Why my code is showing this kind of behavior?
#include <stdio.h>
void s1()
{
int a;
a++;
printf("%d ",a);
}
void s2()
{
int aa;
aa++;
printf("%d ",aa);
}
int main()
{
int i = 0;
for(i = 0; i < 10; i++)
{
s1();
}
for(i = 0; i < 10; i++)
{
s2();
}
return 0;
}
Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Why 'a' in second function is storing value from first function?
When you do not initialize an object with automatic storage duration (such as variables defined inside functions), the C standard does not specify what its value is, or even that it has a fixed value, or even (depending on certain factors) that the behavior of the program is defined.
In your case, it is likely the memory that was assigned for a initially contained zero, and the compiler generated code that used this uninitialized memory. After s1 completed, the program used the same memory for aa, the same way that, if you go the dentist and hang your coat on a hook and later take it and leave, a patient who comes after you may hang their own coat on the same hook. Then, in s2, aa contained the value left over from s1.
In “real world” programs, you are unlikely to see this exact behavior, for several reasons. For one, things will have happened in the program before s1 is called, so the memory used for a is not likely to contain zero. For another, the program will be compiled with optimization, and the compiler will likely use a register for a or aa rather than memory on the stack. Further, with optimization turned on, the compiler may recognize that the behavior is not defined or not fully specified and optimize it to even stranger code. And, finally, professionals compile with many warning options enabled and set to be errors rather than mere warnings, so the compiler reports errors like this before the program is deployed.
Congratulations, you've stumbled into Undefined Behavior. Not the first one either.
When you declare a variable with no initialization. The C standard defines it as Indeterminate Values.
3.19.2
1 indeterminate value
either an unspecified value or a trap representation
Any time you try to use an indeterminate value, you invoke undefined behavior. Anything can happen! It may take another variable's value, it may short out the sun, anything!
The Undefined Behavior section of the C standard lists this as one possible UB-
The value of an object with automatic storage duration is used while it is indeterminate.
When you do a++ (or aa++), you're incrementing the current value of a, the value being indeterminate. And thus, the language has no guarantees on the behavior. Just because it shows one behavior in one machine, doesn't mean it'll show the same behavior in all machines.
What is the output of this program and how?
#include<stdio.h>
int main(){
int a=0,b=10;
a=b---
printf("the value of b=%d",b);
printf("the value of a=%d",a);
return 0;
}
In your code, writing
a=b---
printf("the value of b=%d",b);
is same as
a = b---printf("the value of b=%d",b);
which is an expression with undefined behavior, as an attempt is made to change and use the value of variable b in two subexpressions without a sequence point in between. Hence, the output of this code cannot be justified.
Without the above problem, in general, the syntax is similar to
x = (y--) - (<return value of printf() call>)
which is a perfectly valid syntax.
Note:
Why a = b---<something> is treated as a = (b--) - <something> and not a = b - -- <something> is due to the maximal munch rule.
Strictly speaking, as others have said since this is undefined behaviour, the result could be anything . And while they're right, it doesn't explain why you get this specific answer in this specific compiler.
In practice b will usually be printed as 9, or 10 depending on whether the compiler does the decrememnt first or the printf first.
printf returns the number of characters printed. Which I think is 16 or 17 in this case.
So this is like writing a = (b--) - 16; b is 10 before the decrement and it's a post decrement so this is the value used.
I have defined a variable with an initial value.
When stepping through the code:
I can see the initial value
My function changes the value
When I use the variable later it has the wrong value
What is happening?
Note: this is intended as a reference question for common problems. If the generic answers here don't help you, post a question containing your complete, actual code.
There are several reasons why a variable might not keep a value. While some are arcane and difficult to debug, some of the most common reasons include:
The variable is modified by an interrupt
//---in main()---
unint8_t rxByte = 0;
printf("%d", rxByte); //prints "0"
//---later in Uart0_Rx_Handler()---
rxByte = U0RXREG; //rxByte set to (for example) 55
//---later in main()---
printf("%d", rxByte); //still prints "0"!!!
If a variable is modified by an interrupt handler, it needs to be declared volatile. Volatile lets the compiler know that the variable could be modified asynchronously and that it shouldn't used a cached copy in a register.
//---in main()---
volatile unint8_t rxByte = 0;
printf("%d", rxByte); //prints "0"
//---later in Uart0_Rx_Handler()---
rxByte = U0RXREG; //rxByte set to 55
//---later in main()---
printf("%d", rxByte); //corectly prints 55
Overrunning an array's bounds
There are no checks in C to prevent you from going beyond the bounds of an array.
int array[10];
int my_var = 55;
printf("%d", my_var); //prints "55"
for(i=0; i<11; i++) // eleven is one too many indexes for this array
{
array[i] = i;
}
printf("%d", my_var); // prints "11"!!!
In this case, we go through the loop 11 times, which is one index bigger than the array. In most compilers, this will result in overwriting variables declared after the array (anywhere on the page, they don't even have to be declared on the next line). This scenario can occur in many different circumstances, including multi-dimensional arrays and stack corruption.
Forgetting to dereference a pointer
While trivial, forgetting the asterisk on a pointer when making assignments will not set the variable correctly
int* pCount;
pCount = 10; //forgot the asterisk!!!
printf("%d", *pCount); //prints ??
Masking a variable with the same name
Reusing a variable name in an inner scope (like inside an if/for/while block or inside a function) hides a variable with the same name elsewhere.
int count = 10; //count is 10
if(byteRecevied)
{
int count = U0RXREG; //count redeclared!!!
DoSomething(count);
printf("%d", count); //prints "55"
}
printf("%d", count); //prints "10"
I'd like to add another possible reason to Zack's excellent answer.
Optimisation
This one frequently surprises me. A good optimising compiler will notice when two different variables are never used at the same time, and will optimise the program by giving those variables the same address in memory. When you are stepping through the code, you may see a variable apparently changing in the watch window. But what's really happening is that the variable that shares its address is being written to.
The other trick the compiler pulls is simply getting rid of a variable that it realises isn't necessary. Sometimes you might be doing the equivalent of this in your code:
force_a = mass_a * acceleration_a
force_b = mass_b * acceleration_b
total_force = force_a + force_b
The compiler sees that there's no real need for the variables force_a and force_b, and so changes the code to this:
total_force = (mass_a * acceleration_a) + (mass_b * acceleration_b)
You'll never see force_a and force_b being updates, but you'll still be able to add them to the watch window.
When I step through my program, I'm convinced that some variable or other has the wrong value in it, but when I let my program run through without stepping, it seems to work. Check that this isn't happening to you.
Added:
As Ashish Kulkarni mentioned, you can check this by turning off optimisation.
I came across an interesting output and I'd to know how the computer is working to produce this. I know that whenever you have %d in a string, you should have a variable to accompany it. When I wrote two %d's and only one variable, I expected that the computer would churn out the same value for the %d's, since it had only one variable to draw on, but for some reason, the %d's returned the value for x and the value for the variable xCubed. I want to know why the program returns xCubed without my writing xCubed at the end of the string. Here's the code:
#include <stdio.h>
int cube(int x);
int main(void){
int x = 5;
int xCubed = cube(x);
printf("Why does this number, %d, equal this number %d?", x);
return 0;
}
int cube(int x){
return x * x * x;
}
Thank you!
Your program invokes undefined behaviour. Anything could happen. Possibly the valued returned from the call to cube happens to lie next to the value of x on the stack. Of course, this behaviour being undefined means that any change to your program, or your compiler options, could result in different behaviour.
In any case, you are expected to supply two values. Do so.
printf("Why does this number, %d, equal this number %d?", x, x);
If you compiled your program with full warnings then the compiler would have warned you of your error. And you could even ask your compiler to treat warnings as errors to stop you committing the mistake.
Your program causes undefined behaviour, so anything is possible. It's some quirk of stack/register layout and calling convention for your platform that gives you the results you see.
That is because xCubed happens to be allocated just after x, which means closer to the printf part of the stack (activation frame).
printf is a vararg function, it has no implicit way of knowing how many arguments it was passed. So, when you call printf with two placeholders but just one value supplied, it will read past the first argument expecting a second and "fall" into the stack of the caller, whose nearest content is exactly xCubed.
Just to be clear: this is the reason why your code exhibits that particular behaviour, not the way it is expected to work. You have a serious bug in your code.
This was by good luck. In effect, it is undefined behaviour.
Obviously, in your case the variable xCubed was put onto stack immediately after the free space. Upon doing the printf() call, x was put immediately before that, and then the address of the format string.
If you compile this program with other optimization settings, your compiler might decide to put xCubed somwhere else, or in a register, or omit it altogether, as its value is never used.
I found some code and I am baffled as to how the loop exits, and how it works. Does the program produce a deterministic output?
The reason I am baffled is:
1. `someArray` is of size 2, but clearly, the loop goes till size 3,
2. The value is deterministic and it always exits `someNumber` reaches 4
Can someone please explain how this is happening?
The code was not printing correctly when I put angle brackets <> around include's library names.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
int main() {
int someNumber = 97;
int someArray[2] = {0,1};
int findTheValue;
for (findTheValue=0; (someNumber -= someArray[findTheValue]) >0; findTheValue++) {
}
printf("The crazy value is %d", findTheValue);
return EXIT_SUCCESS;
}
Accessing an array element beyond its bounds is undefined behavior. That is, the program is allowed to do anything it pleases, reply 42, eat your hard disk or spend all your money. Said in other words what is happening in such cases is entirely platform dependent. It may look "deterministic" but this is just because you are lucky, and also probably because you are only reading from that place and not writing to it.
This kind of code is just bad. Don't do that.
Depending on your compiler, someArray[2] is a pointer to findTheValue!
Because these variables are declared one-after-another, it's entirely possible that they would be positioned consecutively in memory (I believe on the stack). C doesn't really do any memory management or errorchecking, so someArray[2] just means the memory at someArray[0] + 2 * sizeof(int).
So when findTheValue is 0, we subtract, then when findTheValue is 1, we subtract 1. When findTheValue is 2, we subtract someNumber (which is now 94) and exit.
This behavior is by no means guaranteed. Don't rely on it!
EDIT: It is probably more likely that someArray[2] just points to garbage (unspecified) values in your RAM. These values are likely more than 93 and will cause the loop to exit.
EDIT2: Or maybe someArray[2] and someArray[3] are large negative numbers, and subtracting both causes someNumber to roll over to negative.
The loop exits because (someNumber -= someArray[findTheValue]) doesnt set.
Adding a debug line, you can see
value 0 number 97 array 0
value 1 number 96 array 1
value 2 number 1208148276 array -1208148180
that is printing out findTheValue, someNumber, someArray[findTheValue]
Its not the answer I would have expected at first glance.
Checking addresses:
printf("&someNumber = %p\n", &someNumber);
printf("&someArray[0] = %p\n", &someArray[0]);
printf("&someArray[1] = %p\n", &someArray[1]);
printf("&findTheValue = %p\n", &findTheValue);
gave this output:
&someNumber = 0xbfc78e5c
&someArray[0] = 0xbfc78e50
&someArray[1] = 0xbfc78e54
&findTheValue = 0xbfc78e58
It seems that for some reason the compiler puts the array in the beginning of the stack area, then the variables that are declared below and then those that are above in the order they are declared. So someArray[3] effectively points at someNumber.
I really do not know the reason, but I tried gcc on Ubuntu 32 bit and Visual Studio with and without optimisation and the results were always similar.