C语言宏定义技巧
出处:http://blog.chinaunix.net/uid-14022540-id-2849095.html
1.宏中"#"和"##"的用法
一、一般用法
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
#include <stdio.h> #define CONS(a,b) ((int)(a##e##b))
#define STR(s) #s int main()
{
printf("%s\n",STR(ABC));
printf("%d\n",CONS(,));
return ;
}
/*
root@oucaijun:/work/dcc# gcc *.c; ./a.out
ABC
2000
*/
二、当宏参数是另一个宏时: 需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开.
1, 非'#'和'##'的情况,自然展开:
#define TOW (2)
#define MUL(a,b) (a*b)
printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW));
这行的宏会被展开为:
printf("%d*%d=%d\n", (2), (2), ((2)*(2)));
MUL里的参数TOW会被展开为(2).
2, 当有'#'或'##'的时候,用'#'或'##'的地方宏参数不会再展开:
#define A (2)
#define CONS(a,b) ((int)(a##e##b) )
printf("%s\n", CONS(A, A)); // compile error
这一行则是:
printf("%s\n", int(AeA));
然而解决这个问题的方法很简单. 加多一层中间转换宏: 凡是涉及到#, ## 的宏,使用另一个宏来包装它。
#include <stdio.h> #define _GET_FILE_NAME(f) (#f)
#define GET_FILE_NAME(f) _GET_FILE_NAME(f) int main()
{
// 根据GET_FILE_NAME(f)的定义,它并没有直接使用#,因此内部宏得以完整地展开,得到正确结果。
static char FILENAME[] = GET_FILE_NAME(__FILE__);//"test.c"
printf("%s\n", FILENAME); // _GET_FILE_NAME(f)在展开的时候,引用了宏 __FILE__
// 根据_GET_FILE_NAME的定义,它的内部遇到宏并不会展开,而只是把其当作字符串而已,得不到正确的结果
static char FILENAME2[] = _GET_FILE_NAME(__FILE__);//__FILE__
printf("%s\n", FILENAME2); return ;
}
/*
root@oucaijun:/work/dcc# gcc *.c; ./a.out
"test.c"
__FILE__
*/
2.宏跟踪调试
#include <stdio.h>
#include <time.h> int main()
{
time_t t;
time(&t); printf("file:%s, line:%d, function:%s, msg:%s, date:%s\n", \
__FILE__, __LINE__, __FUNCTION__,"hello", ctime(&t)); return ;
}
/*
root@oucaijun:/work/dcc# gcc *.c; ./a.out
file:1.c, line:11, function:main, msg:hello, date:Tue Jul 21 17:03:01 2015
*/
当定义了_DEBUG,输出数据信息和所在文件所在行 #include <stdio.h>
#include <time.h> #define _DEBUG #ifdef _DEBUG
#define DEBUGMSG(msg, date) \
do{\
printf("msg: %s; file:%s, line:%d, date:%s\n",msg, __FILE__, __LINE__, date);\
}while() #else
#define DEBUGMSG(msg,date)
#endif int main()
{ time_t now;
time(&now); DEBUGMSG("hello",ctime(&now)); return ;
}
/*
root@oucaijun:/work/dcc# gcc *.c; ./a.out
msg: hello; file:1.c, line:22, date:Tue Jul 21 17:05:44 2015
*/
3.下面列举软件中常用得一些宏定义:
1,防止一个头文件被重复包含
#ifndef COMDEF_H
#define COMDEF_H
//头文件内容
#endif
2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植.
typedef unsigned char boolean; /* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short uint16; /* Unsigned 16 bit value */
typedef unsigned char uint8; /* Unsigned 8 bit value */
typedef signed long int int32; /* Signed 32 bit value */
typedef signed short int16; /* Signed 16 bit value */
typedef signed char int8; /* Signed 8 bit value */
typedef unsigned char byte; /* Unsigned 8 bit value type. */
typedef unsigned short word; /* Unsinged 16 bit value type. */
typedef unsigned long dword; /* Unsigned 32 bit value type. */
3,得到指定地址上的一个字节或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
4,求最大值和最小值
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
7,按照LSB格式把两个字节转化为一个Word
#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
8,按照LSB格式把一个Word转化为两个字节
#define FLOPW( ray, val ) \
(ray)[0] = ((val) / 256); \
(ray)[1] = ((val) & 0xFF)
12,将一个字母转换为大写
#define UPCASE( c ) ( ((c) >= 'a' && (c) = '0' && (c) = '0' && (c) = 'A' && (c) = 'a' && (c) (val)) ? (val)+1 : (val))
20,宏定义防止使用是错误
用小括号包含.
用do{}while(0)语句包含多语句防止错误
eg: #define ADD(a,b) do{a+b;\
a++;}while(0)
C语言宏定义技巧的更多相关文章
- C语言宏定义技巧——多次包括头文件内容不同
1. 头文件定义例如以下: /* declears in "funcs.h" */ FUNC_1(ID_FUN1_001) FUNC_1(ID_FUN1_002) FUNC_2( ...
- 将C语言宏定义数值转换成字符串!
将C语言宏定义转换成字符串! 摘自:https://blog.csdn.net/happen23/article/details/50602667 2016年01月28日 19:15:47 六个九十度 ...
- C 语言宏定义
C 语言宏定义1.例子如下: #define PRINT_STR(s) printf("%s",s.c_str()) string str = "abcd"; ...
- C语言 宏定义之可变参数
可变参数宏定义 C99编译器标准允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏.可变参数宏就像下面这个样子: #define dbgprint(. ...
- C语言宏定义使用技巧
写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等.下面列举一些成熟软件中常用得宏定义...... 1.防止一个头文件被重复包含 #ifndef COMDEF_ ...
- 【转】C语言宏定义的几个坑和特殊用法
总结一下C语言中宏的一些特殊用法和几个容易踩的坑.由于本文主要参考GCC文档,某些细节(如宏参数中的空格是否处理之类)在别的编译器可能有细微差别,请参考相应文档. 宏基础 宏仅仅是在C预处理阶段的一种 ...
- C 语言宏定义函数编写时 do-while 的妙用和一些注意事项
在 C 语言中,我们都知道可以用宏定义来编写函数,一般称为宏函数.如果一个宏函数比较复杂,那么在编写这样的宏函数是有一定技巧和注意事项的.文章给出一些我认为值得关注的地方,以及一些注意事项(个人建议) ...
- C语言宏定义时#(井号)和##(双井号)的用法1
#在英语里面叫做 pound 在C语言的宏定义中,一个#表示字符串化:两个#代表concatenate 举例如下: #include <iostream> void quit_comman ...
- C语言宏定义时#(井号)和##(双井号)的用法
C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结. 关于#和## 在C语言的宏中,#的功能是将其后面 ...
随机推荐
- Jmeter接口測试
一.创建project.引包 1.创建JAVAproject 2.引入Jmeter中lib\ext基础包:ApacheJMeter_java.jar.ApacheJMeter_core.jar 3.引 ...
- jQuery也能舞出绚丽的界面(完结篇)
ThematicMap又增加了两种Chart类型,现在总算是齐全了,效果也出来了,与大家分享一下: 1.MultiSelect选择界面: 颜色框是可以选择颜色的: 2.生成的饼图效果: 3.生成的柱状 ...
- String的几种比较方法对比(Compare,CompareTo, CompareOrdinal、Equals)
String类字符串比较大概有4种方法:Compare(),CompareTo(), CompareOrdinal()和Equals(). Compare()方法是CompareTo()的静态版本.而 ...
- LINQ 图解
LINQ 图解 原创地址:http://www.cnblogs.com/jfzhu/archive/2013/01/01/2841332.html 转载请注明出处 LINQ,语言集成查询(Langua ...
- Java跨域以及实现原理
最近研究了一下跨域,没接触之前我的印象就是配合单点登录的一种方式,后来在网上看到资料才知道不仅仅是这一种,用法很多,具体的可以去网上搜索. 一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访 ...
- Arduino M0 的一个坑(2015-12-25)
前几天收到 Arduino M0,试各项功能都正常,可就是串口监视器/串口助手不能显示程序里打印的输出,好生奇怪,各种换波特率各种PC串口程序换着试,资料不多,官方资料也只说到 Serial1 用于 ...
- Jquery调用webService的四种方法 转载-记录
我总结几个关键点 1. 服务必须声明为ScriptService(否则会出现下面的问题) 2.服务的方法不需要任何更改,保持原状 3.客户端用jquery的.ajax方法来调用 3.1 type必须是 ...
- Qt见解:Post 与 Get 的区别(Get将参数直接与网址整合为一个整体,而Post则将其拆为两个部分)
第一次接触Qt的Http项目,今天看了一下Post和Get的基本使用方法,就开始尝试了.原先以为Post专门用于向服务器发送请求,然后接收服务器应答的: 而Get只是单纯从服务器获取资源,比如下载这个 ...
- 动态规划 最长公共子序列 LCS,最长单独递增子序列,最长公共子串
LCS:给出两个序列S1和S2,求出的这两个序列的最大公共部分S3就是就是S1和S2的最长公共子序列了.公共部分 必须是以相同的顺序出现,但是不必要是连续的. 选出最长公共子序列.对于长度为n的序列, ...
- 基于visual Studio2013解决C语言竞赛题之0307函数求值
题目 解决代码及点评 这又是个条件函数,但是这个函数无法用switch来解决,因为switch只能用于和某条件相等情况下,而这个函数的范围是无穷的 遇到这种问题,我们还是需要用复合的if语 ...