이젠 좀 외우자!
Defining macros is a little trickier than calling them. For instance, does the definition of f
in
#define f (x) ((x) - 1)
represents
(x) ((x) - 1)
but, does not apply to macro calls. just to macro definitions.
Thus after the last definition above, f(3)
and f (3)
both evaluate to 2
.
#define max(a, b) ((a) > (b) ? (a) : (b))
/* i can be increased twice */
biggest = max(biggest, n[i++]);
max(a, max(b, max(c, d)))
/* will be expanded to */
((a)>(((b)>(((c)>(d)?(c):(d)))?(b):(((c)>(d)?(c):(d)))))?
(a):(((b)>(((c)>(d)?(c):(d)))?(b):(((c)>(d)?(c):(d))))))
#define assert(e) if (!e) assert_error(__FILE__, __LINE__)
if (x > 0 && y > 0)
assert (x > y);
else
assert (y > x);
will cause dangling-else problem. The right way to define assert()
is: make the body of assert()
look like an expression and not a statement:
#define assert(e) \
((void) ((e) || _assert_error(__FILE__, __LINE__)))
책에는 소개되지 않았으나 do ~ while(0)
을 통해 compound statement
를 안전하게 작성할 수 있다:
#define assert(e) \
do { \
if (!e) \
assert_error(__FILE__, __LINE__); \
} while (0)
#define FOOTYPE struct foo
FOOTYPE a;
FOOTYPE b, c;
Using a macro definition for this has the advantage of portability - any C compiler supports it. But it is better to use a type definition:
typedef struct foo FOOTYPE;
Consider the following example:
#define T1 struct foo *
typedef struct foo *T2;
T1 a, b;
/* is equal to
struct foo *a, b;
*/
T2 c, d;
/* is equal to
struct foo *c, *d;
*/
https://www.mythos-git.com/Cruzer-S/CTAP/-/tree/main/Chapter06
[Book] C Traps and Pitfalls (Andrew Koenig)
[Site] 네이버 영영, 영한사전
[Site] https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html