1

Going over some code (written in the C language) I have stumbled upon the following:

//we have a parameter

uint8_t num_8 = 4;

//we have a function

void doSomething(uint32_t num_32) {....}

//we call the function and passing the parameter

doSomething(num_8);

I have trouble understanding if this a correct function calling or not. Is this a casting or just a bug?

In general, I know that in the C / C++ languages only a copy of the variable is passed into the function, however, I am not sure what is actually happening. Does the compiler allocates 32 bits on the stack (for the passed parameter), zeros all the bits and just after copies the parameter?

Could anyone point me to the resource explaining the mechanics behind the passing of parameter?

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
Max Z
  • 87
  • 1
  • 1
  • 10
  • 4
    It's an [implicit conversion](https://en.cppreference.com/w/c/language/conversion). – Fred Larson Apr 16 '19 at 15:23
  • 3
    Some of your answer is dependant on the architecture and procedure call standard upon it, on ARM platforms for instance the parameter would usually be passed in R0 rather than on the stack. – Colin Apr 16 '19 at 15:24
  • Calling conventions can also vary [by OS](https://stackoverflow.com/q/18135871/10077). – Fred Larson Apr 16 '19 at 15:34

1 Answers1

2

As the function declaration includes a parameter type list, the compiler knows the type of the expected parameter. It can then implicitely cast the actual parameter to the expected type. In fact the compiler processes the function call as if it was:

doSomething((uint32_t) num_8);

Old progammers that once used the (not so) good K&R C can remember that pre-ansi C only had identifier lists and the type of parameters was not explicitely declared. In those day, we had to explicitely cast the parameters, and when we forgot, we had no compile time warnings but errors at execution time.

The way the cast and the call is precisely translated in assembly language or machine instruction is just an implementation detail. What matters is that everything must happen as if the compiler had declared a temporary uint32_t variable had coerced the uint8_t value into the temporary and had passed the temporary to the function. But optimizing compilers often use a register to pass a single integer parameter. Depending on the processor, it could zero the accumulator, load the single byte in the low bits and call the function.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252