The resultant code is what the compiler sees. It is more useful during debugging to be able to examine the results of these two steps individually. If in doubt, macroexpand-1 it out. To control evaluation of the arguments. What macros can do that functions cannot is to control when the arguments get evaluated.
Functions evaluate all of their arguments before entering the body of the function.
Macros don't evaluate any of their arguments at preprocessor time unless you tell it to, so it can expand into code that might not evaluate all of the arguments. For example, suppose that cond was in the language, but if wasn't, and you wanted to write a version of if using cond . The problem with this is that it always evaluates all of its arguments, while the semantics of if dictate that exactly one of the Then and Else arguments gets evaluated. A replacement for IF, takes 2 or 3 arguments. If the first evaluates to non-NIL, evaluate and return the second.