Are calls to a function done by reference?

Frankthetech

Well-known member
Hi, I'm trying to figure out how these two code blocks differ.
Code:
void dotWait(int toWait){
  uint32_t startMillis=millis();
  while(millis()<=(startMillis+toWait)){
    Serial.print(".");
    delay(200);
  }
  Serial.println();
}

Code:
void dotWait(int &toWait){
  uint32_t startMillis=millis();
  while(millis()<=(startMillis+toWait)){
    Serial.print(".");
    delay(200);
  }
  Serial.println();
}

the first function takes the int toWait without the & sign, both work but the 1 with the & compiles a few bytes larger.
Is one way better/safer.
 
Normally the first way is used. It makes a copy of "toWait" which is used inside that function.

The second function is indeed a reference, so it's actually using the "toWait" variable from the calling code. Usually this isn't done unless there is some compelling need. It doesn't modify that variable. Normally you would add "const" if you're never going to modify the referenced variable.
 
Note that some coding standards require all reference parameters to be const. The same coding standards use pointers if you want to change the calling variable. I don’t always agree with this, but you might find this in the wild.

Example: void dotWait(const int& toWait)
 
For all fundamental types (int, float, etc.), use the first form (pass by value) when you do not intend to modify the argument. An additional advantage is that this allows you to pass literal constants as arguments. It is also often the fastest method, since the first few arguments are frequently passed in CPU registers (depending on the calling convention), and the value is ready for use without requiring dereferencing.

Const references generally only make sense when passing large objects, because a reference is typically implemented as a pointer and therefore avoids the cost of copying.

There is a web page: https://godbolt.org/ (Compiler Explorer) that allows you to enter a code snippet and see how it is compiled to machine code using various compilers and options. When using GCC or GNU C++, be sure to enable optimizations with -O2 or -O3; otherwise, the generated code will be unoptimized.
 
Last edited:
The question then
Why does the compiled code become 8 bytes larger when the reference type is used?
If it makes a copy (pass by value) I might expect it to be larger.

Code:
//pass test1

//void dotWait(int toWait){    //compiles ->59672 bytes    ram->9444
void dotWait(int& toWait){    //compiles ->59680 bytes    ram->9444
  uint32_t startMillis=millis();
  while(millis()<=(startMillis+toWait)){
    Serial.print(".");
    delay(200);
  }
  Serial.println();
}

void setup() {
  int dly=3000;
  uint32_t strtMillis=millis();
  Serial.begin(115200);
  while(!Serial){}
  Serial.print("time to start serial = ");
  Serial.print(millis()-strtMillis);
  Serial.println(" milli sec");
  dotWait(dly);

}

void loop() {

}
 
When you pass by value, it puts 3000 (a constant value that can be encoded directly in an instruction) in a register and jumps to the function.
When you pass by reference, 3000 is stored to a memory location, the address of that memory is put into a register, then it jumps to the function. The extra step requires more instructions.
 
In anticipation of the next question, when the referenced variable is local to the calling function, its memory will be temporarily allocated on the stack. That's why you see exactly the same number for RAM used for variables. A reference does indeed use extra memory compared to just passing a constant, but in this case the variable is among the "free for local variables" number in memory usage report.
 
Back
Top