C语言:认识带参数宏

认识带参数宏

定义

性质

优缺点

带参数宏实例

例1 模拟函数:求两个数中的最大者

#include <stdio.h>

#define MAX(x,y) ((x)>(y)?(x):(y))

int main(void)
{
    int i, j;

    i = 100;
    j = 98;

    printf("Macro MAX(%d, %d) called: %d\n", i, j, MAX(i, j));
    return 0;
}

输出:

Macro MAX(100, 98) called: 100

例2 模拟函数:判断一个数是不是偶数

#include <stdio.h>

#define IS_EVEN(n) ((n)%2 == 0)
int main(void)
{
    int i;

    i = 100;
    printf("Macro IS_EVEN(%d) called: %d\n", i, IS_EVEN(i));

    i = 97;
    printf("Macro IS_EVEN(%d) called: %d\n", i, IS_EVEN(i));
    return 0;
}

输出:

Macro IS_EVEN(100) called: 1
Macro IS_EVEN(97) called: 0

例3 带参数宏模拟函数:将小写字母转成大写字母

#include <stdio.h>

#define TOUPPER(c) ('a'<=(c) && (c)<='z'? (c)-'a'+'A': c)

int main(void)
{
    char a1 = 'b';
    printf("Macro TOUPPER(%c) called: %c\n", a1, TOUPPER(a1));

    char a2 = 'B';
    printf("Macro TOUPPER(%c) called: %c\n", a2, TOUPPER(a2));

    return 0;
}

输出:

Macro TOUPPER(b) called: B
Macro TOUPPER(B) called: B

例4 带参数宏模拟函数:简单显示整数

#include <stdio.h>

#define PRINT_INT(n) printf("%d\n", n);

int main(void)
{
    int i,j;

    i = 11;
    j = 2;

    PRINT_INT(i/j);

    return 0;
}

例5 带参数宏模拟函数:输出带有标签的整数

#include <stdio.h>

#define PRINT_INT(n) printf(#n" = %d\n", n);

int main(void)
{
    int i,j;

    i = 11;
    j = 2;

    PRINT_INT(i/j);

    return 0;
}

解释:

  • #运算符:将宏的一个参数转换为字符串常量。

例6 泛型MAX宏定义
源文件generic_max.c

#include <stdio.h>

#define GENERIC_MAX(type)          \
type type##_max(type x, type y)    \
{                                  \
    return x > y? x : y;           \
}

float float_max(float x, float y);

int int_max(int x, int y);

int main(void)
{
    float x, y;

    x = 97.0f;
    y = 100.0f;
    printf("function float_max(%f, %f) called: %f\n", x, y, float_max(x, y));

    int i, j;

    i = 100;
    j = 98;
    printf("function int_max(%d, %d) called: %d\n", i, j, int_max(i, j));

    return 0;
}

GENERIC_MAX(float)

GENERIC_MAX(int)

截取预处理后文件generic_max.i的片段:








float float_max(float x, float y);

int int_max(int x, int y);

int main(void)
{
 float x, y;

 x = 97.0f;
 y = 100.0f;
 printf("function float_max(%f, %f) called: %f\n", x, y, float_max(x, y));

 int i, j;

 i = 100;
 j = 98;
 printf("function int_max(%d, %d) called: %d\n", i, j, int_max(i, j));

 return 0;
}

float float_max(float x, float y) { return x > y? x : y; }

int int_max(int x, int y) { return x > y? x : y; }

输出:

function float_max(97.000000, 100.000000) called: 100.000000
function int_max(100, 98) called: 100

解释:

  • ##运算符:将两个tokens(比如标识符)粘在一起形成一个token。

例7 追踪函数的调用

#include <stdio.h>

#define FUNCTION_CALLED() printf("%s called\n", __func__);
#define FUNCTION_RETURNS() printf("%s returns\n", __func__);

void f(void);

int main(void)
{
    f();
    return 0;
}

void f(void) 
{
    FUNCTION_CALLED();

    printf("hello world f()\n");

    FUNCTION_RETURNS(); 
}

输出:

f called
hello world f()
f returns

解释:

  • 标识符__func__:存储的是当前正在执行的函数的名字的字符串。

例8 可变参数宏

#include <stdio.h>

#define TEST(condition,...) ((condition)? \
  printf("Passed test: %s\n", #condition): \
  printf(__VA_ARGS__))

int main(void)
{
    int voltage, max_voltage;

    max_voltage = 120;
    voltage = 125;

    TEST(voltage <= max_voltage,
        "Voltage %d exceed %d\n", voltage, max_voltage);

    voltage = 98;
    TEST(voltage <= max_voltage,
         "Voltage %d exceed %d\n", voltage, max_voltage);
    return 0;
}

输出

Voltage 125 exceed 120
Passed test: voltage <= max_voltage

解释:

  • __VA_ARGS__:表示与省略号对应的参数,且只能出现在具有可变参数的宏的替换列表中;

例9 区分同一程序的不同版本
在程序开始放置如下语句:

printf("compiled on %s at %s\n", __DATE__, __TIME__);
#include <stdio.h>

int main(void)
{
    printf("compiled on %s at %s\n", __DATE__, __TIME__);
    return 0;
}

输出:

compiled on Apr  6 2020 at 09:24:12

解释:

  • __DATE__:编译的日期,格式为"mm dd yyyy";
  • __TIME__:编译的时间,格式为"hh:mm:ss";

例10 查找出错的代码行数和文件
macrotest4.c

#include <stdio.h>

#define CHECK_ZERO(divisor)  \
  if (divisor == 0)  \
    printf("*** Attempt to divide by zero on line %d  "\
        "of file %s *** \n", __LINE__, __FILE__);

int main(void)
{
    int i,j;

    i = 100;
    j = 0;

    CHECK_ZERO(j);
    return 0;
}

输出:

*** Attempt to divide by zero on line 15  of file macrotest4.c *** 

解释:

  • __FILE__:被编译的文件名
  • __LINE__:被编译的文件中的行号
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容