-4

I made this small code in C:

#include <stdio.h>

int alo();

int main()
{
    printf ("%d",alo());
}

int alo(int i, int x)
{
   return (x);
}

but it seems when I run it without giving any argument to alo it prints a completely random number.

I just want to know, since I suppose it can't be 100% random, what number is this in reality and where does it come from, and also if I can predict it. Note that this is pure curiosity.

I guess it has something to deal with memory reading, but how this particular bug exactly functions?

Cœur
  • 37,241
  • 25
  • 195
  • 267
KeroK
  • 5
  • 1
  • 8
    [undefined behaviour](https://en.wikipedia.org/wiki/Undefined_behavior) – George Mar 28 '17 at 17:04
  • 2
    You have called a function with fewer parameters (zero) than it requires (two). This yields undefined behavior. In this case, that means that the C language standard explicitly disclaims any explanation of what the function does or returns, or indeed of what the whole program does. That is, there is *definitively* no answer to your question at the level of generality at which it is posed. – John Bollinger Mar 28 '17 at 17:06
  • 1
    The *likely* thing is that it's either a value from memory near the top of the stack, or it's the value that happened to be in some register that's used to pass that parameter. But the exact behavior depends on the machine architecture, OS, compiler, and compiler version *at a minimum*. – hobbs Mar 28 '17 at 17:10
  • 1
    It has something to do with knowing the language, paying heed to warnings and writing correct code. – too honest for this site Mar 28 '17 at 17:10
  • But I agree: there's no 100% random in nature – Jack Mar 28 '17 at 17:11
  • @hobbs: There is no guaranteed behaviour for undefined behaviour. – too honest for this site Mar 28 '17 at 17:11
  • `int alo();` by default disables parameter check (in other words compiler wont assume anything about parameters). user `int alo(void);` compiler then throws an error. –  Mar 28 '17 at 17:17
  • Random output? What did you expect it to print, when you didn't tell it? – Weather Vane Mar 28 '17 at 17:18
  • 1
    @Olaf yes, everyone is well aware of that. However perhaps you do understand that a compiler is a computer program and that it *has* a behavior that we can talk about, even when that behavior isn't guaranteed by the fine folks at ISO, and that there's nothing to be gained by shouting "undefined behavior is undefined!!!1111!1one" in the middle of such discussion. – hobbs Mar 28 '17 at 17:22
  • 2
    @hobbs: The compiler does not execute the code. It can emit any code, including one which uses unspecified register or memory values. There is no use telling an obvious beginner his UB code will behave like this or that. It is potentially ddangerous, becuase beginners tend to take this for granted and rely on it. Read other questions where users insist on UB has to show a specific behaviour, because someone told him. – too honest for this site Mar 28 '17 at 17:25
  • @Binary_10, that's not a very satisfactory description. `int alo()` says that the function accepts a fixed but unspecified number of arguments, of unspecified types. It provides no basis for argument type checking, but it does not actively *disable* checking. Where there is another declaration in scope that provides parameter types -- whether earlier or later -- that declaration will provide a suitable basis. – John Bollinger Mar 28 '17 at 17:42
  • @olaf that UB gives no guarantees is a useful observation in the *design* of a system, where avoiding UB is essential to guarantee correctness. It is, however, beyond utterly useless as an explanatory tool when you have already invoked UB and want to understand what happened. UB is the "here be dragons" at the edge of the map, but computers are (nearly) deterministic machines, dragons aren't real, and we can get or make ourselves a better map of the territory, and continue the journey of understanding, instead of trying to ward off evil spirits with magic words. – hobbs Mar 28 '17 at 17:53
  • 1
    @hobbs it's not unreasonable for a developer to investigate what exactly is happening during specific umm... 'episodes' of UB. It is, however a waste of time and effort for SO users to get involved with unknown compilers, unknown linkers, unknown loaders and unknown hardware. If the program is run on an abacus, bead-counting would be the recommended invertigative technique. Slightly more recent devices may need JTAG debugger hardware. There is no point in getting involved with UB unless you are sitting at the hardware. – ThingyWotsit Mar 28 '17 at 18:34
  • @hobbs: I couldn't have phrased that better than ThingyWotsit did. Just that: OP is apparently a beginner. For a beginner a detailed explanation with implementation-specific (like using a stack) is pointless. He first has to understand he did something wrong and why. Once more experienced he should be able to investigate further what's going on in his environment with a debugger. – too honest for this site Mar 28 '17 at 20:57

2 Answers2

5

Your alo function accepts (i.e. requires!) two parameters, but you called it without any arguments. The behavior is undefined in this case.

You declared your function (before main) without a prototype. This means that it is your responsibility to supply the correct number of arguments of correct type in all calls to alo. The compiler will not help you to verify the correctness of such calls.

For this reason a good idea is to1 always declare your functions with prototypes

int alo(int i, int x);

so that the compiler will help you to ensure that you are calling your function properly.


In practice the implementation of alo blindly follows its parameter passing convention and reads the storage location that is supposed to contain the value of parameter x. The resultant value is retuned from alo.

What kind of storage location is used for passing x depends on the implementation details. It could be a memory area or a CPU register. Whatever residual/garbage value was residing in that storage location before the call is returned from alo.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • I'm not so sure supplying the correct arguments to a function declared as `int foo()` but defined as `int foo( TYPE1 a, TYPE2 b )` is sufficient. Wouldn't the arguments to calls in code using that declaration be subject to default argument promotion, while the defintion would expect the actual *defined* argument type? For example, `int foo(); char a; foo(a);`, then *define* the function as `int foo( char z )`. Wouldn't `a` be subject to promotion to `int` while `foo()` expects to have a `char` passed? See http://stackoverflow.com/a/1255818/4756299 – Andrew Henle Mar 28 '17 at 17:29
  • 1
    @Andrew Henle: Certainly. In order for such a call to be correct, the parameter types must match the argument types after *default argument promotions*. Which means that prototype-less functions sould not be defined with parameters of "small" types, like `char`, `float` etc. In this case I'm talking about the specific example of `alo`. – AnT stands with Russia Mar 28 '17 at 17:33
  • Thanks for the edit, makes this an answer worth upvoting. – hobbs Mar 28 '17 at 17:55
  • the code didn't compile for me and gives linker error: Error 1 error LNK2019: unresolved external symbol "int __cdecl alo(void)" (?alo@@YAHXZ) referenced in function _main – Fatemeh Karimi Mar 28 '17 at 18:56
  • 1
    @Fatemeh Karimi: This is a C question. Yet it appears that you are trying to compile this code as C++. It won't normally compile as C++. Only as C. (It is invalid in C as well, but in a different way.) – AnT stands with Russia Mar 28 '17 at 19:08
-1

OK, Google for:

you own hardware architecture, (CPU, registers, memory etc), assembler, machine code, instruction set, debugger, stack, calling convention, parameters, arguments

When you understand the above, you are equipped to investigate the UB on the computer that it manifests on. Next box, next architecture, next week, it may behave differently:(

ThingyWotsit
  • 366
  • 2
  • 4