C语言中宏定义使用方法详解

C语言中的宏替换详解

首先看一个问题:

#include <stdio.h>

#define    PRINT_CLINE()    printf("%d", ______)

int main(void)

{

PRINT_CLINE();

PRINT_CLINE();

return 0;

}

在横线处填上适当的代码,使得上面这段代码的输出为34。

我想一般人看到这个问题的时候头脑里都没有明确的思路来解答这个它。我看到这个问题的时候想出了各种办法来解答它,最终还是没有通过编译器的检查,比如我想过的其中一个办法是:

(int static i=2, i++)

想着在这个位置定义一个static变量,并且赋上初值为2,最后在加上一个i++,根据逗号运算符的运算规则,整个表达式的值应该是最后一项的值,想法确实很完美,但是这样是通不过编译器的!在这个位置使用一条定义变量的语句是不合法的!想了很久实在想不出来办法了。于是重新整理了宏定义的使用方法,终于找到了答案。下面一步步来说宏定义的使用方法:

1.最简单的替换

#defind    Pi    3.14159

上面的这条语句就是比较常用的简单替换了,在预处理阶段,程序代码中出现Pi的地方都被替换为后面的3.14159。

2.带参数的宏替换

#define    MAX(a, b)    (a)>(b)?(a):(b)

这个就是带参数的宏替换了,在代码中使用MAX宏的时候,括号内部的参数会跟随到宏替换中。当然这个替换需要注意的地方就是记得为每个参数加上(),不然可能会产生边际效应。

3.字符替换符:#@

先看下面的这段代码:

#include <stdio.h>

#define PT_CHAR(x) printf("%c", #@x);

int main(void)

{

PT_CHAR(d);

return 0;

}

程序的输出为d。或许你会问,那直接将宏定义中的#@x用x替换掉不就可以了么,粗略的一看这样的说法确实是可以的,但是宏替换的时候PT_CHAR(d)编译器会认为d是一个传递的参数,既然d并非一个常量,那么编译器就只好认为它是一个变量了,但是这样的话问题就出来了,d并没有定义过!

4.字符串宏替换符:#

这个跟上面的有点类似了,比如下面的两行代码片段:

#define PT_STRING(x) printf("%s", #x)

PT_STRING(Hello!);

如果想要达到输出为Hello!的目的,就要使用#x,如果不使用的话根据前面的分析,编译器会把Hello!整体理解为一个变量,但是即便这样理解的话,这个!也是不能作为变量的一部分的啊,所以编译器会报出比较多的错误。

5.连接宏替换符:##

#define   p(n)   printf("symbol"#n"=%d", symbol##n)

int   symbol9 = 9;

p(9);

上面的输出为symbol9=9,symbol##n将symbol和n(也就是传递过来的9)连接起来,构成了变量symbol9。

6.ANSI标准中的几个标准预定义宏

__LINE__:在源代码中插入当前源代码行号;

__FILE__:在源文件中插入当前源文件名;

__DATE__:在源文件中插入当前的编译日期

__TIME__:在源文件中插入当前编译时间;

__STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;

__cplusplus:当编写C++程序时该标识符被定义。

看到这里,上面的问题答案也就出来了,标准预定义宏中的__LINE__代表了源代码在改代码中的行号,使用这个宏就可以很方便的实现上面的功能了。

答案:#define    PRINT_CLINE()    printf("%d", __LINE__-4)

时间: 2024-08-02 15:12:25

C语言中宏定义使用方法详解的相关文章

C语言中宏定义(#define)时do{}while(0)的价值(转)

C语言中宏定义(#define)时do{}while(0)的价值 最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总结了一下讨论,加上自己的理解,do{...}while(0)的价值主要体现在: 1. 增加代码的适应性 下面的宏定义没有使用do{...}while(0) #define FOO(x) foo(x); bar(x); 这样宏定义,单独调用不会出现问题,例如: FOO(100) 宏扩展后变成: 1 f

oc中字典的实现方法详解

一:字典的基本概念 Foundation中的字典(NSDictionary,NSMutableDictionary)是由键-值对组成的数据集合.正如,我们在字典里查找单词的定义一样. 通过key(键),查找的对应的value(值),key通常是字符串对象,也可以是其他任意类型对象.在一个字典对象中,key的值必须是唯一的. 此外,字典对象的键和值不可以为空(nil),如果需要在字典中加入一个空值,可以加入NSNull对象 二:不可变字典-NSDictionary 1:初始化(以一个元素和多个元素

Swift使用WKWebView在iOS应用中调用Web的方法详解

这篇文章主要介绍了Swift使用WKWebView在iOS应用中调用Web的方法详解,使用WKWebView便等于使用和Safari中相同的JavaScript解释器,用来替代过去的UIWebView,需要的朋友可以参考下 自从iOS8开始,Apple引入了WKWebView欲代替UIWebView.相比而言,WKWebView消耗内从更少,功能也更加强大.让我们来看看WKWebView怎么使用吧! 0.初始化(1)首先需要引入WebKit库 复制代码代码如下: #import <WebKit/

并发编程(六)Object类中线程相关的方法详解

一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详解 */ public class MyNotify { // 在多线程间共享的对象上使用wait private String[] shareObj = {"true"}; public static void main(String[] args) { MyNotify test =

C语言中宏定义之 ## 用于可变参数

GCC 支持复杂的宏,它使用一种不同的语法,使你可以给可变参数一个名字,如同其它参数一样,比如: 引用 #define debug(format, args...) fprintf(stderr, format, args) 这种定义可读性更强,也更容易描述.完整测试代码: 引用 #include <stdio.h> #define debug(format, args...) fprintf(stderr, format, args) int main(){    char a[20] = 

c语言中宏定义#和 ##的作用:

转载:http://www.cnblogs.com/cyttina/archive/2013/05/11/3072969.html 看了这篇文章后了解了,但是文章中的例子比较特别,我在这里加个注释好了. http://www.cnblogs.com/welkinwalker/archive/2012/03/30/2424844.html 单井号就是将后面的 宏参数 进行字符串操作,就是将后面的参数用双引号引起来 双井号就是用于连接. 比如文章中的例子: #define PRINT(NAME) p

.Net语言中关于AOP 的实现详解

来源: IT人家  发布时间: 2011-03-22 20:28  阅读: 3546 次  推荐: 2   原文链接   [收藏] 摘要:该文章主要和大家讲解开发应用系统时在.Net语言中关于AOP 的实现. 文章主要和大家讲解开发应用系统时在.Net语言中关于AOP 的实现.LogAspect完成的功能主要是将Advice与业务对象的方法建立映射,并将其添加到Advice集合中.由于我们在AOP实现中,利用了xml配置文件来配置PointCut,因此对于所有Aspect而言,这些操作都是相同的

[51单片机] Keil C51中变量的使用方法详解

引言    8051内核单片机是一种通用单片机,在国内占有较大的市场份额.在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功.由于51内核单片机的存储结构的特殊性,Keil C51中变量的使用与标准C有所不同.正确地使用变量,有利于获得高效的目标代码.下面详细介绍Keil C51中变量的使用方法. 1 CPU存储结构与变量的关系    变量都需要有存储空间,存储空间的不同使得变量使用时的工作效率也不同.    标准C的典型运行环境是8086(含IA-32系列)内核,其存储结构是CP

PHP 中 16 个魔术方法详解

前言 PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __construct(),类的构造函数 __destruct(),类的析构函数 __call(),在对象中调用一个不可访问方法时调用 __callStatic(),用静态方式中调用一个不可访问方法时调用 __get(),获得一个类的成员变量时调用 __set(),设置一个类的成员变量时调用 __isset(),当对不可访问属性调用isset()或emp