How Arduino IDE pre-processing work?

The preprocessor is a "textual" pass through the source code. For example, you've seen something like:

#define MAXARRAYSIZE  100

If you have an expression in your code that reads:

for (i = 0; i < MAXARRAYSIZE; i++) {

when the preprocessor finishes, it's as though you wrote:

for (i = 0; i < 100; i++) {

The advantage, of course, is that you only need to change the #define to everywhere change the affected value in the source code. The preprocessor also reads function prototypes, like:

int myFunction(int val, char *buff);

and constructs an attribute list much like a symbol table that allows it to check all subsequent uses of that function for the correct argument list (i.e., an int and a pointer) and that the return value is used as an int. If also expands any macros you may have written, like:

#define ARRAYSIZE(x)   (sizeof(x) / sizeof(x[0]))

so when you write:

for (i = 0; i <  ARRAYSIZE(buff) ; i++) {

the preprocessor expands it to:

for (i = 0; i <   (sizeof(buff) / sizeof(buff[0])) ; i++) {

I think it helps to simply think of the preprocessor as performing textual replacements, macro expansions, and type checking via prototypes.