Inline Functions
An inline function is a special type of C++ function that the compiler inserts directly at the point of call rather than performing a standard function call. This can reduce the overhead of function calls, thereby improving performance.
#include <iostream>
using namespace std;
int func(int v1, int v2) {
return v1 + v2;
}
inline int addValues(int val1, int val2) {
return val1 + val2;
}
int main() {
func(1, 2);
addValues(3, 4);
return 0;
}
Advantages of Inline Functions
- Performance improvement: Inline functions reduce the overhead associated with function calls.
- Reduced code size: Inline functions can reduce the overall size of the code since no additional function call instruction are generated.
- Improved readability: Inline functions enhance readability by placing the function code directly where it is used.
Use Cases
- When the function is small in size.
- When the function is called frequently.
References
A reference in C++ is a powerful mechanism that allows you to access variables indirectly in an efficient and type-safe way. References are similar to pointers but have several key differences:
- References must be initialized: A reference must be initialized either at the time of declaration or shortly after.
- References cannot be rebound: Once a reference is initialized, it cannot point to a different variable.
- References share storage space with the variable they refer to: Modifying a reference also modifies the original variable.
- References are safer compared to pointers.
A reference can be considered as a "weaker" pointer, effectively providing an alias for a variable.
Example of using references
#include <iostream>
using namespace std;
// Using pointers
void swapPointers(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// Using references
void swapValues(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x1 = 1, x2 = 2;
int x3 = 3, x4 = 4;
swapPointers(&x1, &x2);
cout << "x1 = " << x1 << ", x2 = " << x2 << endl;
swapValues(x3, x4);
cout << "x3 = " << x3 << ", x4 = " << x4 << endl;
getchar();
return 0;
}
Assembly Analysis
Main Function
Passing by Pointers
Passing by References
As shown above, references and pointers are fundamentally similar, but references provide additional constraints and simplifications. For example, when combined with const, they can protect memory spaces and allow direct manipulation of specific memory locations without the need for address-taking or dereferencing.
All data on the stack must be moved into CPU registers before any computation can occur. Similarly, function return values are stored in registers.
In 32-bit systems, a pointer occupies 4 bytes, while in 64-bit systems, it occupies 8 bytes. To further demonstrate their similarity, let's perform a size check.
Why place a reference inside a structure to calculate its size?
Writing it this way would be incorrect.
As mentioned earlier, a reference acts like an alias for a variable. Therefore, outputting the size of 'a' (an int) would not yield the size of the reference itself.
To further illustrate that references are essentially pointers, consider the following example:
int value = 10;
int& ref = value;
ref = 20;
----
C7 45 F4 0A 00 00 00 mov dword ptr [value],0Ah ;int value = 10;
8D 45 F4 lea eax,[value] ;int& ref = value;
89 45 E8 mov dword ptr [ref],eax
8B 45 E8 mov eax,dword ptr [ref] ;ref = 20;
C7 00 14 00 00 00 mov dword ptr [eax],14h
--------------------------------------------------
int num = 10;
int* ptr = #
*ptr = 20;
---
C7 45 DC 0A 00 00 00 mov dword ptr [num],0Ah ;int num = 10;
8D 45 DC lea eax,[num] ;int* ptr = #
89 45 D0 mov dword ptr [ptr],eax
8B 45 D0 mov eax,dword ptr [ptr] ;*ptr = 20;
C7 00 14 00 00 00 mov dword ptr [eax],14h
Due to CPU architecture, memory addresses must be loaded into registers before any operation can be performed.
Assembly
Two Formats
Intel format and AT&T format are two different syntaxes used in x86 assembly language. Intel format, developed by Intel, is the most commonly used syntax. It follows these conventions:
- Instruction mnemonics come before operands.
- Registers are represented by single-letter abbreviations (e.g.,
eax,ebx). - Memory addresses are enclosed in square brackets (e.g.,
[eax]).
AT&T format, developed by Bell Labs, is primarily used in Unix and Unix-like systems. It follows these conventions:
- Instruction mnemonics come after operands.
- Registers are prefixed with a percent sign (e.g.,
%eax,%ebx). - Memory addresses are enclosed in parentheses (e.g.,
(%eax)).
Here is the same assembly code written in both formats:
Intel format:
mov eax, 10
add eax, 5
AT&T format:
movl $10, %eax
addl $5, %eax
QuickStart
- When performing calculations, the CPU must first load values into registers before operating on them.
- RAX, RBX, RCX, and RDX are general-purpose registers in 64-bit systems, each occupying 8 bytes.
- The contents within
[]represent addresses. wordtakes up 2 bytes,dwordtakes up 4 bytes, andqwordtakes up 8 bytes.- Function calls:
callinstruction jumps to the actual function address.
This is because the call instruction does not directly jump to the function's actual address. Enstead, it performs the following steps: 1. Pushes the return address onto the stack. 2. Jumps to the function's actual address.
When debugging a call instruction in assembly, the first step is a push eip operasion. Continuing execution will eventually lead to the jmp instruction, which then moves to the function's actual address.
mov dword ptr [ebp - 8], 3(operand, memory unit, variable identifier, address, value)xoris used for bit-wise operations;xor eax, eaxis often used to clear a register.inc opis equivalent toop++.pushinstructions beforecallare typically used for passing parameters.- ESI (source index register) and EDI (destination index register) are commonly used in x86 for string and memory copy operations.