#define n 17Unlike everything else in C++, "n" is now defined as 17 from this point onwards, even across scope like classes or functions. Declaring "int n=3;" gets rewritten to "int 17=3;", which won't compile! To avoid this, by convention macros are written in capital letters, like "NUM_ELEMENTS", not just bare n.
return n;
(Try this in NetRun now!)
#define n 10+10This returns 10+10*10+10 = 120. What?!
return n*n;
(Try this in NetRun now!)
#define n (10+10)This works, but you must remember to do it every time!
#define times3(x) x*3Again, the problem is this is a plain text replacment. So calling the same macro with a sum:
return times3(10);
return times3(10+10);This returns... 40. Thats 10+10*3, not (10+10)*3. Again, the fix is to wrap the expression in parenthesis. Note that arguments and the overall expression both need parenthesis, to protect against operators inside or outside the macro call:
#define times3(x) ((x)*3)This works basically reliably, although there's not much benefit to using a macro over using a small function here.
return times3(10+10);
#define begin {A FORTRAN programmer used to typing in ALL CAPS might be more comfortable using #define FOR for.
#define end }
int x=5;
if (x>3)
begin
return 7;
end
#define BOOGA int x=9; return (x&In addition to screwing up any syntax highlighting editor, this basically destroys the readability of the code, and is bad enough to make people seriously talk of banning all macros.
BOOGA 7);
#define quote(string) #string
std::cout<<quote(This stuff goes in as a string...)<<std::endl;
I use stringification all the time for GPU programming, where the
graphics driver wants the GPU code as a string. I can have the same
code work in C++ directly, then have a macro spit out a stringified
version for the GPU to run.
#define checkErrs(code) { int err=code; /* run */ if (err!=0) std::cout<<"Error in "<<#code<<" at line "<<__LINE__<<" of file "<<__FILE__<<"\n"; }This macro definition looks a little better using backslashes to separate the lines:
int x=18;
checkErrs(x-18);
checkErrs(x-10);
return 0;
(Try this in NetRun now!)
#define checkErrs(code) { \I need the curly braces to be able to declare "int err" repeatedly. But now people typically add an extra semicolon at the end of the macro call; this is untidy, and will throw off an "if..else" statement with the macro in the middle. There's a bizarre well-known solution, which is to add a worthless do{}while(0) that only exists to consume the semicolon:
int err=code; /* run */ \
if (err!=0) { \
std::cout<<"Error "<<err<<" in '"<<#code<<"' at line "<<__LINE__<<" of file "<<__FILE__<<"\n"; \
} \
}
#define checkErrs(code) do { \Another trick I use a lot is to generate classes inside a macro. For example, if my calculator needs ten "operator" classes for each of the basic operators, instead of typing them all out I'll generate them with a macro like this:
int err=code; /* run */ \
if (err!=0) { \
std::cout<<"Error "<<err<<" in '"<<#code<<"' at line "<<__LINE__<<" of file "<<__FILE__<<"\n"; \
} \
} while(0)
#define makeop(name,op) \The nice part is now if you need the calcop classes to inherit from some base class, you can add it to the macro. Forgot the "const" in calculate? Just add it to the macro. To add a "getSymbol" method returning the operator's symbol, you can use stringification to add it to the macro definition like "const char *getSymbol(void) const { return #op; }". If each operator needs to be registered into the list of operators, you can add that as well.
class calcop_##name { public: \
int calculate(int a,int b) { return a op b; } \
}
makeop(add,+);
makeop(sub,-);
makeop(mul,*);
makeop(div,/);
makeop(and,&);
makeop(or,|);
makeop(left,<<);
makeop(right,>>);
int foo(void) {
calcop_add a;
return a.calculate(100,10);
}
(Try this in NetRun now!)
%define deplacer mov eax,
%define retour ret
deplacer 3
retour
Note that "deplacer" is half an instruction--macros don't care about syntax.
The wide variety of macros supported by NASM is listed in Chapter 4 of the NASM manual. Briefly, this is:
%macro printit 1 ; calls print_long with its argumentI built a little stack tracing macro named "s" that you can use to watch the stack grow and shrink:
mov rdi,%1 ; copy macro argument 1 into parameter register
extern print_long
call print_long
%endmacro
mov rcx,23
printit rcx
ret
(Try this in NetRun now!)
%include "lib/trace_s.S" ; defines a tricky stack tracing macro named "s"Various weird things that are handy in function-like macros include:
s push 7
s push 3
s add rsp,16
s ret
(Try this in NetRun now!)