I have written a little program:
#include <stdio.h>
void tester() {
int x = 69;
}
void x() {
int x;
printf("%d\n", x);
}
int main() {
tester();
x();
}
which I expect to print out 69. It prints out 69 when I compile without optimization, but with O1-O3, it prints out large numbers. Why is this?
Attempting to read an uninitialized variable that never had its address taken triggers undefined behavior, which basically means that the program is not required to behave in any particular way.
It's clear that you were attempting to have the uninitialized variable x in the function x to get the "left over" value of x in tester. With optimization disabled this is how it happens to work. With optimization enabled, the compiler takes advantage of undefined behavior to assume it does not happen and make certain optimizations based on that fact.
So with optimization enabled, the compiler is basically assuming you won't read an uninialized variable which is why you see different output.
those 2 x variable are totally different things, they just happen to have the same name. If you want it to be the same x then you must create a global variable
int x;
void tester() {
x = 69;
}
void xx() {
printf("%d\n", x);
}
int main() {
tester();
xx();
}
Related
Here's a code:
#include <stdio.h>
/* declaration */
int square (int num);
int main() {
int x, result;
x = 5;
result = square(x);
printf("%d squared is %d\n", x, result);
return 0;
}
/* definition */
int square (int num) {
int y;
y = num * num;
return(y);
}
And when I change it like this:
#include <stdio.h>
/* declaration */
int main() {
int x, result;
x = 5;
result = square(x);
printf("%d squared is %d\n", x, result);
return 0;
}
/* definition */
int square (int num);
int square (int num) {
int y;
y = num * num;
return(y);
}
I get the warning:
Implicit declaration of the function 'square'
Does this warning has any relation with the branch prediction things? Does the former code improves branch prediction and hence the performance of the code (as the function call branches/diverts the execution from the normal execution of the code!?)
No, it has nothing to do with branch prediction.
The language requires that a declaration of a function appear before the function is called. The compiler needs to see the declaration in order to generate code for the function call that is even correct, let alone performant: to know what types are expected as parameters, what type is returned, how the parameters should be laid out in the stack and registers, and so on. And by the one-pass design of the C language, this means the declaration has to appear before the function call. It's true that the necessary information is further down in the source file, but that's too late - the compiler isn't designed to "peek ahead" for it.
In modern C, the absence of the declaration makes the program invalid, and the compiler must issue a diagnostic. Previous versions of the C language allowed such a program to compile, using an "implicit declaration" which was essentially a standard set of rules to guess what types were expected and returned, and how they should be passed. Some compilers, such as gcc, proceed under these earlier rules when they find a missing declaration, and only give a warning instead of an error (which complies with the requirement for a diagnostic). But as the programmer, you really should consider it an error, since there's a good chance that the "guessed" implicit declaration will be wrong for your function, in which case the compiled program may fail in unpredictable ways at runtime.
i want to understand why output in this code is 10 not 20
#include<stdio.h>
#include <stdio.h>
int check (int, int);
int main()
{
int c;
c = check(10, 20);
printf("c=%d\n", c);
return 0;
}
int check(int i, int j)
{
int *p, *q;
p=&i;
q=&j;
i>=45?*p:*q;
}
The problem here is that the return value of the check() function is undefined behavior.
In order to get the expected output of 20 you would have to use the return statement like this return i>=45?*p:*q;
You need to do this to actually tell the compiler to write the result to the return register.
If you don't do this the function simply exits without explicitly writing the result value to the return register. Instead the register content is simply left in the state it was last in (in your case 10), but this is in no way guaranteed and will very likely vary with the compiler used.
If you really want to understand it on an instruction level have a look here: godbolt compiler explorer
There on the right you can see the x86 assembly of your program, and if you look closely you can see that the compiler just so happens to use the eax register to compare the value which is also by ABI convention the register used for function return values.
I sometimes want to show my students that local variables have to be initialized before use. But on some occasions they get the initial value of zero without being initialized. So my students don't believe me. For example in this code.
#include <stdio.h>
int main(void){
int sum;
sum += 5;
printf("%d", sum);
return 0;
}
Sometimes output is 5. To demonstrate the undefined behaviour of not initialising the variable sum to zero I am looking for an example.
Pointing to standards is good. But I understand your desire to show an example to your students. I'm not sure about the best way; but to increase your chances of seeing the undefined behavior, you can declare multiple variables that cannot easily be optimized away by the compiler.
#include <stdio.h>
void main(){
int sum1;
int sum2;
int sum3;
int sum4;
int sum5;
int sum6;
int sum7;
int sum8;
int sum9;
int sum=sum1+sum2+sum3+sum4+sum5+sum6+sum7+sum8+sum9;
printf("%d\n",sum);
}
On my system; recent Ubuntu, with recent GCC this produces incorrect results on every run, whereas your original example always produced 5. But I can't make any guarantees for your system.
Memory is usually initialized to zero when a process is started. Otherwise, you would get old memory contents from another process, which would be a security risk. Because of this, code like this will, in my experience, usually print zero:
#include <stdio.h>
int main(void) {
int x;
printf("%d\n", x);
}
You have a greater chance to get non-zero results if you use memory that has been used by your own process. For example, I just got non-zero printouts with this program:
#include <stdio.h>
void f(void) {
int x;
printf("%d\n", x);
}
int main(void) {
f();
f();
f();
}
But remember that according to the standard, the contents of an uninitialized local variable (with storage class auto) is undefined, so a compiler is allowed to always set its variables to zero. Or -4.
How about explicitly setting the value for a certain position and reading it from another uninitialized variable pointing at the same position?
#include <stdio.h>
void foo()
{
int x = 1234;
}
void bar()
{
int y;
printf("%d\n", y);
}
int main()
{
foo();
bar(); /* Will print out 1234 */
}
It would be better to not prove your students something by your self instead use C standards.
C99 section 6.7.8 Initialization:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
This question already has answers here:
What happens when a variable goes out of scope?
(3 answers)
Closed 6 years ago.
I am studying the working of an automatic variable. I know that it is only accessible inside the block or function in which it is declared and its lifetime is within that same function or block. So the following piece of code I am trying to check.
/Declaration of header files/
void testfn(void);
int *p;
int main(void)
{
testfn();
print("%d\n",*p);
return 0;
}
void testfn(void)
{
int x=444;
p=&x;
}
The output is - 444
I am wondering that when the testfn(); exits,the variable x will be destroyed. Then how in main function the pointer (*p) prints 444.
How this works...or if I am missing something.
Please clarify my doubt.
Thanks
It is coincidence that the original value still remains. With another compiler, or with another compilation configuration, it could take any other value or the program could just crash.
If between the testfn and printf functions you call any other function that does something with its local variables, you might see that the 444 value is not obtained anymore. But this is just, again, coincidence.
p points to the stack where x was stored. If the memory location hasn't been used for something else you will most likely get 444.
Try to insert another function call before printing p and see what happens:
#include <stdio.h>
#include <math.h>
void foo() {
int y=123;
}
void testfn(void);
int *p;
int main(void)
{
testfn();
foo();
printf("%d\n",*p);
return 0;
}
void testfn(void)
{
int x=444;
p=&x;
}
On my machine, the output is now:
123
Since the code results in undefined behaviour, the result could be different if I try this on another platform. But you can see that undefined behaviour can lead to strange bugs.
The memory location that was previously reserved for variable x is not overwritten yet. But it may be at any time. That's why your code leads to undefined behaviour.
In the following example, the memory location that was previously reserved for variable x will be overwritten by the value that is assigned to the variable y. Since the pointer p still points to that location, *p will evaluate to this new value:
#include <stdio.h>
int *p;
void test1(void) {
int x = 444;
p = &x;
}
void test2() {
int y = 15;
}
int main(void) {
test1();
test2();
printf("%d\n",*p);
return 0;
}
The fact that the value still remains is completly coincidental (not guaranteed) because nothing has overwritten it yet.
You can not count on this, it may fail, may print garbage or may crash your program or pc even.
Don't use this, it is considered undefined behavior.
I'm having a hard time understanding the ways C handles returned values. Say for example we have:
int one = 0;
one = foo(); // Why isn't one being assigned 10?
// Clearly there is a difference between these two
printf("%d", one); // one is still 0
printf("%d", foo());
int foo()
{
return 10;
}
I can't seem to elucidate why there is a difference, and why one won't work over the other.
Thank you!
The following program's output is 1010. I compiled it with gcc -Wall -std=c99 main.c -o main.exe So, I think it's either your compiler problem, or you were wrong when claimed that printf("%d", one); prints zero.
#include <stdio.h>
int foo(void);
int main()
{
int one = 0;
one = foo();
printf("%d", one);
printf("%d", foo());
return 0;
}
int foo()
{
return 10;
}
The first argument of printf() is a const char *, (a pointer to an array of const char's), and with printf(foo()) you're trying to use a pointer to address 10, which obviously is out of the range of the program, causing it to not work. However, with printf("%d", one) you are telling printf to print out a number, which does work.
C function is not "function" as in math (or as in functional programming).
It just sequence of actions needed to obtain return value, and this mean that function may obtain side effects.
So think about your example - what if foo() will look like this:
int foo()
{
printf("some text");
return 10;
}
In other words, if you use variable with returned value - you just use value, but if you use function call, you do all computations needed for obtaining value.