XOR and minus seems to be about the same in concept, because, as if “A-B” means “difference between A and B”, A^B also means “bitwise difference between A and B”.
Let’s see following two SWAP algorithm. (Analysing following alogrithm will be helpful to understand difference of concept between ‘A-B’ and ‘A^B’).
*x = *x + *y;
*y = *x – *y;
*x = *x – *y;
*x ^= *y;
*y ^= *x;
*x ^= *y;
We should focus on that both of ‘-‘ and XOR are operation to get “difference”.
(‘-‘ is difference of number and XOR is bitwise difference. But, those are all “difference”!)
So, we can implement swap operation with both ‘-‘ and “XOR”.
Here is conceptual description of XOR swap.
*x ^= *y; “Store difference of ‘original x’ and ‘original y'”
*y ^= *x; “We know difference of ‘original x’ and ‘original y'(x). So, we can get ‘original x’ with ‘original y’ and store it into ‘y’.”
*x ^= *y; “We know difference of ‘original x’ and ‘original y'(x), and ‘orignal x'(y). So, we can get ‘original y’ and store it into ‘x’.”
Understanding something is “Understanding it’s basic concept”. It’s very important.!!
So, someone who understands XOR, should be able to infer “swap with XOR” at the moment of knowing about “swap with ‘+/-‘”
Stack can be classified into “Full Stack” and “Empty Stack” by addressing mode.
Full Stack : The stack pointer points to the last item in the stack.
Empty Stack : The stack pointer points to the next free space on the stack.
I prefer Empty Stack because… how can I say… It is more computer-like-expression…. :-)
Usually, in computer science, indexing starts like (i=start) and ends like (i<end)… That is, [a, b) range concept is normal…
In Empty Stack, we can say "Stack is empty" by checking (SP == Framebase). And this is more suitable for above concept…
Ascending Stack : The stack grows upwards, starting from a low address and progressing to a higher address.
Descending Stack : The stack grows downwards, starting with a high address and progressing to a lower one.
Fundamentally, these two are same. But, I prefer descending stack, because when stack is broken, mostly post-stack-section(higher memory address) tends to be broken. So,
– [case1 : current stack has enough free space]
Descending stack is better to detect stack-corruption than ascending stack.
char a; // ---(*1)
memcpy(a, data, len); // len > 10 ---(*2)
If stack space after (*1) is not used, then even if stack is corrupted, it is very difficult to detect in ascending stack.
(because, no one uses corrupted area.) So, debugging is more difficult.
– [case2 : current stack is almost pull]
In descending stack, usually, corrupting stack of specific thread(Thread A) affects it’s own behavior firstly. So, it is easier to debug – same with [case1].
In ascending stack, corrupting stack may affects to other thread’s stack – thread whose stack is just next (higher address) of Thread A – firstly with high possibility (especially, if several stacks are adjacent in memory space). This usually leads to debugging-nightmare