# ===== CodeLab: c-preprocessor =====
# 以下代码片段按文章出现顺序拼接, 共 8 段

# ----- 片段 1 (bash) -----
gcc -E demo.c -o demo.i
wc -l demo.c demo.i
head -n 40 demo.i

# ----- 片段 2 (c) -----
#include <stdio.h>

#define PI 3.14159
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

int main(void) {
    double r = 2.0;
    printf("面积 = %.2f\n", PI * r * r);

    int s = SQUARE(2 + 3);
    printf("SQUARE(2+3) = %d\n", s);   /* 25,不是 11 */

    int m = MAX(3 + 1, 5);
    printf("MAX = %d\n", m);           /* 5 */
    return 0;
}

# ----- 片段 3 (c) -----
#include <stdio.h>

#ifndef DEBUG
#define DEBUG 0
#endif

int main(void) {
#ifdef DEBUG
    printf("[debug] 当前 DEBUG=%d\n", DEBUG);
#endif

#if DEBUG >= 2
    printf("[debug] 详细日志模式\n");
#endif

#if DEBUG >= 3
    printf("[debug] 更啰嗦的跟踪\n");
#endif

    printf("正常业务代码\n");
    return 0;
}

# ----- 片段 4 (c) -----
#ifndef MY_HEADER_H
#define MY_HEADER_H

/* 头文件内容只会在第一次被包含时真正展开 */

#endif /* MY_HEADER_H */

# ----- 片段 5 (c) -----
#include <stdio.h>

/* 反面教材:没加括号 */
#define BAD_SQUARE(x) x * x
/* 正确写法:参数和整体都加括号 */
#define GOOD_SQUARE(x) ((x) * (x))
#define MAX2(a, b) ((a) > (b) ? (a) : (b))

int main(void) {
    printf("%d\n", BAD_SQUARE(2 + 3));   /* 2 + 3 * 2 + 3 = 11,错了 */
    printf("%d\n", GOOD_SQUARE(2 + 3));  /* 25,正确 */

    int i = 3, j = 5;
    int m = MAX2(i++, j++);
    /* 展开后:((i++) > (j++) ? (i++) : (j++))
       比较时 j++ 一次,分支里 j++ 又一次 */
    printf("m=%d i=%d j=%d\n", m, i, j);
    return 0;
}

# ----- 片段 6 (c) -----
#include <stdio.h>

#define DO_IT(x) do { \
    printf("doing %d\n", (x)); \
    fflush(stdout); \
} while (0)

int main(void) {
    int k = 1;
    if (k > 0)
        DO_IT(k);
    else
        printf("不会执行\n");
    return 0;
}

# ----- 片段 7 (c) -----
#include <stdio.h>

#define STR(x) #x
#define CAT(a, b) a ## b

int main(void) {
    printf("%s\n", STR(hello world));   /* 打印:hello world */

    int xy = 100;
    printf("%d\n", CAT(x, y));          /* 展开成 xy,打印 100 */

    int version_major = 3;
    printf("%d\n", CAT(version_, major)); /* 展开成 version_major */
    return 0;
}

# ----- 片段 8 (c) -----
#include <stdio.h>

int main(void) {
    printf("所在文件: %s\n", __FILE__);
    printf("所在行号: %d\n", __LINE__);
    printf("编译日期: %s\n", __DATE__);
    printf("编译时间: %s\n", __TIME__);
#ifdef __STDC__
    printf("遵循标准 C\n");
#endif
    return 0;
}
