C: Why adding int to an empty variable results in random numbers

New to C, when I run this code - something unexpected happens:

#include <stdio.h> int add(); int main(void) { printf("%d\n",add(3)); } int add(int i, int j) { return i+j; } 

I understand that I do not provide the second parameter to the add function. Out of curiosity, however, can someone tell me why a function call with only one parameter continues to return random numbers, for example 2127001435 ... 612806891 ...- 395221029?

+6
source share
6 answers

If you break the rules of the language and the program compiles, its behavior is undefined (i.e., something can happen).

 int add(); 

tells the compiler to let you call add whatever you like, but you still need to make sure that if the function definition accepts two ints , you will call it exactly two ints .

Ads with empty parameters are sometimes useful, but in 99% of cases you want to avoid them.

If you replace the ad with this

 int add(int, int); 

the compiler should save you, or at least warn you about your error.

(In addition, declarations with typed parameters will force the compiler to convert unsuitable parameters, if possible (for example, if you were to call your add function with long ), then with the typed declaration, the long argument will be implicitly converted to int . This will not happen if declaration int add(); ))

+8
source

Most answers focus on technical reasons why you get the results you see. However, for beginners in C, they are probably not very useful answers, as they are a little difficult to understand without experience with C.

A softer explanation is that you need to understand that in C there are some rules that you must follow, and you need to keep promises. If you decide not to follow these rules, the compiler can do whatever it wants. This is what we call undefined behavior.

In your code: int add(); you promised the compiler that there is a function somewhere that returns an int that takes some indefinite number of arguments.

Then you defined a function to take exactly two arguments. So, now you (in a certain sense) promised that the add function will work correctly if you pass exactly two arguments (of type int ).

Later you call the add(3); function add(3); one argument. Since you passed only one argument to a function that is defined as exactly two, the compiler can do whatever it wants (in this case, return random numbers). He can do this because you have broken your promise that you need to pass two add arguments.

As a rule, in order to catch these problems earlier (i.e., the compiler can warn us when we are going to do something stupid), we use more stringent definitions for functions.

Contrast a with b , c , d , which are more strict.

 int a(); // a takes ??? arguments int b(void); // b takes exactly zero arguments int c(int x); // c takes exactly one argument int d(int x, int y); // d takes exactly two arguments 
+8
source

First, we declare foo as a function that takes an indefinite number of arguments and returns an integer:

 int add(); 

We call this one argument:

  add(3) 

But then we define it as taking two arguments:

 int add(int i, int j) { ... } 

Since we named it without providing a second argument, our program has undefined behavior, and therefore unpredictable happens. On your system, the result varies from run to run. On other systems, you can get consistent output, or you can get a runtime error (for example, through a signal).

In the general case, the definition of foo() can be in another translation unit before main() , so the compiler cannot reliably detect this problem in C (in C ++, an argument type signature is part of a functional relationship, so the situation is different there).

+2
source

As the Tangra noted in the comments, the behavior is undefined, so any behavior is acceptable ... but this is not quite what you requested, and a more complete answer conveys several considerations ...

So, although any behavior is acceptable, why do you get this behavior?

Well, a more strict language will not compile this call, because the signature is confused. But C is not a more strict language. It is assumed that you know what you are doing.

What you are doing is telling it to build a stack frame for a function that takes a single integer argument, put the specific value in the right place in the stack frame so that the function sees it as "value for parameter", and then call the function.

But the function expects two arguments. That is, he expects the caller to prepare a stack frame with two integer parameters. Where he expects to find the first, he will find the first. Where he expects to find the second, he discovers ... what was the last value in the memory that would contain the second parameter, if the call were correct.

The stack frame is smaller than expected, and the value for the expected second parameter would be placed at the end of the finished stack frame. So, when a function searches for it, and it finds ... no matter what the random value is. Because the call stack grows and contracts, different calls will find different values.

0
source

In C, a memory block is assigned to a variable. since no value was provided to it, the memory block that was allocated to the variable still contains some value that remains from the previous program. This value identifier is called "GARBAGE VALUE" here, when you add i and j without initializing j, the garbage value is added with i and returned as a result.

-one
source

Many answers are excellent and interrupted for harassment. Taking aboard the tangrs answer: the reason for the detail was to help explain why you get undefined behavior in the context of what the compiler does with your code.

It depends on the platform and the compiler. But, as a rule, for several arguments the called function will expect that the parameters will be in several register registers (or sometimes on the stack). They can have any old garbage in them, depending on what they were last used for. Therefore, if you do not provide a value or an initialized variable that needs to be transferred to them, they will use what values ​​were last "assigned" to them. And someone guesses what these meanings are.

-one
source

Source: https://habr.com/ru/post/1013198/


All Articles