FAQ: How to allocate a matric dynamically?
Method 1:
int* m = (int*)malloc(sizeof(int) * n * m);
// Use m[i * m + j] to access m[i][j]
Method 2:
int* buf = (int*)malloc(sizeof(int) * n * m);
int** m = (int **)malloc(sizeof(int*) * n);
int i;
for(i = 0; i < n; ++i)
m[i] = buf + i * m;
Method 3:
int **m = (int**)malloc(sizeof(int*) * n);
int i;
for (i = 0; i < n; ++i)
m[i] = (int*)malloc(sizeof(int) * m);
Pointer to Function And Event Handling
Let’s take the qsort() routine as an example:
void qsort(void *, size_t, size_t,
int (*)(const void *, const void *));
The qsort() routine doesn’t know how to compare two elements, so it requires a function to tell it which is smaller. Commonly, function pointers works as a server, for a reaction you need the user to define. Such mechanism is called callback.
Let’s look into another example which shows the classic POSIX signal usage:
#include <stdio.h>
#include <signal.h>
void handle_zero(int p)
{
puts("blabla");
signal(SIGFPE, handle_zero);
}
int main()
{
int i = 0;
int j = 1;
signal(SIGFPE, handle_zero);
j /= i;
raise(SIGFPE);
}
Dinner: Memory, Stack and Calling convention
When an arithmetic exception is raised,
handle_zero will be called.
raise a SIGFPE exception
raise a SIGFPE exception manually
Stack and Heap
int main()
{
int *p = malloc(sizeof(int));
int i;
...
}
BSS: Better Save Space
int m[1000000];
int n[1000000] = {1};
int main()
{
int m1[1000000];
int n1[1000000] = {1};
return 0;
}
Each int[1000000] takes 4M space. How large should the .exe file be? The answer is, 4M.
Both supposed to be in file, but as BSS implied, uninitialized variable is omitted.
Both in stack, allocated when main is called.
Alignment
Consider the following structure:
struct A
{
char c1;
int c2;
char c3[5];
};
sizeof(struct A) = 1 + 4 + 5 = 10?
In my project, it’s 16, in order to accelerate the addressing access. In 32 bits environment, CPU accesses address of a multiple of 4 is much faster. The compiler adds padding bytes in the structure, so that the size of the structure would be a multiple of 4.
Calling Convention
Some questions about function call:
l What happened before a function is called?
n Pass arguments with stack or register.
n Push the address of the next function.
n Jump to the function.
l What do a called function do?
n Get the arguments (if any).
n Do the work.
n Clean up the stack (optional).
n Pop the saved address and jump to it.
l What happened after a function is called?
n Clean up the stack (optional)
And what’s calling conventions?
l Argument-passing order
l Stack-maintenance responsibility
l Name-decoration convention
l …
Example:
The cdecl calling convention
Argument-passing order:
Right to left
Stack maintenance responsibility:
Calling function pops the arguments from the stac
Name-decoration convention:
Underscope character (_) is prefixed to names
Apply the calling conventions to the folloing code:
int main()
{
...
f(1, 2);
...
}
_main
push 2 into stack
push 1 into stack
push the address of the next instruction into stack
goto _f
_f
get parameters and do the work
pop the return address and return
_main
pop the 1 and 2 from the stack
Other Conventions:
stdcall: Win32 API
Stack maintenance responsibility:
Called function pops the arguments from the stac
fastcall: FAST call
Argument-passing order:
The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left.
Stack maintenance responsibility:
Calling function pops the arguments from the stac
Variational Arguments
int sum(int num, ...)
{
??? how to get ... argument?
}
int main()
{
int a = 1, b = 2, c = 3;
int n = sum(3, a, b, c); // n = 6 expected.
}
Cdcel And Stdcall Pass Arguments Right to Left
When sum is called, the stack must be like:
The setjmp is used to save the current environment, while the longjmp is used to restore the saved environment. So that, we need a data structure to hold the “environment”.
Firstly, save EBP, so that EBP can be used to save the initial value of ESP which always points to the top of the stack. After this, the stack grows, which means ESP changes. And now, the valid range of the stack is from EBP + 4 to ESP. So, saving bytes from EBP to EBP + 4 saves the returning address.