: macros associate names with code fragments
#define PI 3.1415
: macro definitions can have parameters
#define RADTODEG(x) ((x)*57.2958)
: macro definitions can be layered
#define DEGTORAD(x) ((x)*PI/180)
: often encode small programming idioms
https://en.wikipedia.org/wiki/Macro_(computer_science)
- Lexical macro expansion textually replaces macros by their definitions
1) pre-processor scans the program text
2) on #define, macro definition is extracted and stored
3) if a name is macro-defined, it is expanded: macro parameters replaced by expanded arguments
4) if a name is not macro-defined, it is copied to output
- Macros vs. Functions
1) macros look like functions ... and macro expansion looks like function inlining
but macro arguments and bodies can be arbitrary code fragments
2) macros can create new names and definitions ("token pasting")
#define ACCEPT(IF) \
public void accept(IF##visitor v){ \
v.visit(this); \
}
http://stackoverflow.com/questions/9104568/macro-vs-function-in-c
- Macros as Syntax Extensions
1) macros can be used to hide coding idioms in syntax
2) need to find out what can be generalised ... and replace by macro parameters
! note: foreach is not a true statement
c code | vector<AST*>& n = tree.getChildren(); for( vector<AST*>::iterator it = n.begin(); it != n.end(); ++it ) { (*it)->accept(*this); }; |
c code with macro | #define foreach(iv, BType, c, CType) \ for( CType<BType>::iterator iv = c.begin(); iv != c.end(); ++iv ) int main(){ ... foreach(it, AST*, n, vector) { (*it)->accept(*this); }; } |
- Lexical macro expansion can cause hard-to-spot errors
1) operator priorities can interfere with complex macro arguments and bodies
#define DEGTORAD(x) x*3.1415/180
DEGTORAD(a-b) => a-b*3.1415/180
=> proper bracketing of macro arguments
#define DEGTORAD(x) (x)*3.1415/180
DEGTORAD(a-b) => (a-b)*3.1415/180
=> outer brackets required to make macro work in all operator contexts
2) macro body can interfere with surrounding syntax
#define SWAP(x,y) t=x;x=y;y=t
if(a>b) SWAP(a,b); else SWAP(b,a); => if(a>b) t=a;a=b;b=t; else t=b;b=a;a=t;
=> proper "packaging" of macro body
#define SWAP(x,y) do{ t=x;x=y;y=t; }while(0);
if(a>b) SWAP(a,b); else SWAP(b,a); => if(a>b) do{ t=a;a=b;b=t; }while(0); else do{ t=b;b=a;a=t; }while(0);
3) side effects in macro arguments can by duplicated
#define MIN(x,y) (((x)<(y)) ? (x) : (y))
x = MIN(a++, b++); => x = (((a++)<(b++)) ? (a++) : (b++));
=> use local temporary variables
4) variable declarations in body can capture arguments
#define SWAP(T,x,y) { T t=x;x=y;y=t; }
int t=0; int s=1; SWAP(int,t,s); => int t=0; int s=1; { int t=t;t=s;s=t; }
=> "obfuscation" of local variables
#define SWAP(T,x,y) { T _t__SWAP=x;x=y;y=_t__SWAP; }
int t=0; int s=1; SWAP(int,t,s); => int t=0; int s=1; { int _t__SWAP=t;t=s;s=_t__SWAP; }
2. Macro Hygiene
: A macro is called hygienic if its expansion cannot cause any collisions with any context
- syntactic hygiene (= no capture of argument parts)
1) guarantees structural integrity of expanded code
2) syntax macros use syntax trees to guarantee structural integrity
=> macro body must be syntactically well structured
=> macro body not necessarily compilation unit
=> c pre-processor needs to be language-aware: must parse macro bodies
- variable hygiene (= no capture of identifiers)
1) guarantees referential integrity: names refer to the "right" objects
2) hygienic macros use renaming to guarantee referential integrity
=> usual solution: obfuscation
! does not prevent "unlucky capture"
! does not prevent repeated introduction of names through repeated macro invocations in the same scope
=> better solution: bound renaming of introduced names
! must be done for every macro invocation
! must be done before arguments are instantiated
- type hygiene
1) guarantees type integrity
https://en.wikipedia.org/wiki/Hygienic_macro
http://blog.theincredibleholk.org/blog/2013/06/17/what-is-macro-hygiene/
댓글 없음:
댓글 쓰기