编译器识别预定义的 ANSI/ISO C99 C 预处理宏,Microsoft C++ 实现将提供更多宏。这些预处理器宏不带参数,并且不能重新定义。

ANSI 兼容的预定义宏

__FILE__,__LINE__,__func__,__DATE__,__TIME__,__TIMESTAMP__
 
1 . __FILE__,__LINE__,__FUNCTION__或者__func__

__FILE__:当前程序行所在源文件名称,标准C支持,该宏当做字符串对待;
__LINE__:当前程序行所在源文件内的行号,标准C支持,该宏当做整形对待;
__FUNCTION__或者__func__:当前程序行所属的函数名称,C99支持(如:VC++6.0不支持),该宏当做字符串对待;

结合打印日志功能,这些信息将有助于调试。简单的使用方法:

//将该程序保存为test.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
printf("FILE:%s|LINE:%d|FUNCTION:%s|%s\n", __FILE__, __LINE__, __FUNCTION__, __func__);
return 0;
}

执行上述程序将打印:FILE:test.cpp|LINE:8|FUNCTION:main|main

特别说明,据参考资料中关于__func__的信息称,__func__不是一个宏,它是编译隐式声明的常量字符数组:static const char __func__[] = "function-name"。

2 . __DATE__,__TIME__,__TIMESTAMP__

__DATE__:当前文件的编译日期,格式是Mmm:dd:yyyy。该宏当做字符串对待。

__TIME__:当前文件的编译时间,格式是hh:mm:ss。该宏当做字符串对待。

__TIMESTAMP__:当前源文件的最近一次的修改日期和时间,格式是Ddd Mmm Date hh:mm:ss yyyy 。该宏当做字符串对待。

编译源文件时,假如该宏,可以让程序打印出编译时间,达到区分不同版本的目的。简单使用方法如下:

#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
printf("DATE:%s|TIME:%s|TIMESTAMP:%s\n", __DATE__, __TIME__,__TIMESTAMP__);
getchar();
return 0;
}

执行上述程序将打印:DATE:Oct 20 2010|TIME:23:33:24。

不重新编译程序的情况下,每次执行该程序打印的都将是是这个时间,而不是系统的当前时间。

3 -- #line

#line用于重置由__LINE__和__FILE__宏指定的行号和文件名。比如说我们有这么一个测试程序:

//将该程序保存为test.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
#line 100 "baidu.cpp"
printf("FILE:%s|LINE:%d\n", __FILE__, __LINE__);
return 0;
}

注释掉第8行代码,程序打印:FILE:test.cpp|LINE:9
不注释第8行代码,程序打印:FILE:baidu.cpp|LINE:100

可见:#line指定下行代码的起始行号和源文件名称,作用域到文件末尾或者再次#line的使用处。

4 -- __GUNC__

__GUNC__,是GCC编译器的预定义,表明当前GNUC编译的版本。__GNUC__ 的值表示gcc的版本,需要针对gcc特定版本编写代码时,可以使用该宏进行条件编译。

6 -- 宏定义的"#"和"##"使用方法

"#":替换宏参数时,将其后面的宏参数转换成带引号的字符串,例如:

#define STR(s) #s
int main()
{
std::string str = STR(abcdefg);
return 0;
}

C编译器在预处理代码时,第5行实际翻译成:std::string str = "abcdefg";

"##":将该符号前后的两个宏参数连接在一起,比如:

#define PRINT(PRINT_FUNNAME, VAR) print_##PRINT_FUNNAME(VAR)
int main()
{
PRINT(common, 5);
return 0;
}

C编译器在预处理代码时,第5行实际翻译成:print_common(5);

我们实际看下综合运用的例子:

//#include <iostream>
#define PRINT(fun, name, var) print_##fun(#name, var)
void print_common(const std::string & name, int var)
{
std::cout << name << ":" << var << std::endl;
}
void print_tofile(const std::string & name, int var)
{
char sz_temp[];
memset(sz_temp, , sizeof(sz_temp));
snprintf(sz_temp, sizeof(sz_temp), "%s:%d", name.c_str(), var);
FILE * fp = fopen("./log.log", "w");
fwrite(sz_temp, , strlen(sz_temp), fp);
fclose(fp);
}
int main()
{
PRINT(common, age, );
PRINT(tofile, age, );
return ;
}

这个代码的意思是,在主函数中以统一的调用入口"PRINT"该宏函数,通过制定不同的函数名称,将变量的名称和值打印到不同的地方,比如屏幕或者文件中。
我们使用g++ -E marco.cpp预处理命令查看下预处理后的源文件:

#  "marco.cpp"
# "<built-in>"
# "<command line>"
# "marco.cpp"
void print_common(const std::string & name, int var)
{
std::cout << name << ":" << var << std::endl;
}
void print_tofile(const std::string & name, int var)
{
char sz_temp[];
memset(sz_temp, , sizeof(sz_temp));
snprintf(sz_temp, sizeof(sz_temp), "%s:%d", name.c_str(), var);
FILE * fp = fopen("./log.log", "w");
fwrite(sz_temp, , strlen(sz_temp), fp);
fclose(fp);
}
int main()
{
print_common("age", );
print_tofile("age", );
return ;
}
 

C/C++预定义宏的更多相关文章

  1. C预定义宏

    作用:对于__FILE__,__LINE__,__func__这样的宏,在调试程序时是很有用的,因为你可以很容易的知道程序运行到了哪个文件的那一行,是哪个函数. 下面一个例子是打印上面这些预定义的宏的 ...

  2. 预定义宏,C语言预定义的宏详解

    1.预定义宏 对于预定义宏,相信大家并不陌生.为了方便处理一些有用的信息,预处理器定义了一些预处理标识符,也就是预定义宏.预定义宏的名称都是以"__"(两条下划线)开头和结尾的,如 ...

  3. 关于标准C语言的预定义宏

    标准C语言预处理要求定义某些对象宏,每个预定义宏的名称一两个下划线字符开头和结尾,这些预定义宏不能被取消定义(#undef)或由编程人员重新定义.下面预定义宏表,被我抄了下来.__LINE__  当前 ...

  4. VC 预定义宏

    列出预定义的 ANSI C和C++ Microsoft实现宏. 编译器识别预定义的ANSI C宏,并且Microsoft C++实现提供几个更多.这些宏不带参数,并且不能重定义.下面列出的某些预定义的 ...

  5. OS X以及iOS中与硬件环境相关的预定义宏

    由于现在ARM处理器的飞速发展,从Apple A4到现在的Apple A7,从32位到64位,每一代处理器几乎都增加了不少特性,从而在架构上也有所不同.比如Apple A6引入了ARMv7S架构,增加 ...

  6. xcode中的预定义宏

    [xcode中的预定义宏] 1.SRCROOT,是定义本target的proj的路径. 2.OBJROOT,对象文件根路径,对象文件(即obj文件)就是中间的临时文件.中间文件输出目录的名字以“pro ...

  7. 关于window PC机的预定义宏win32

    MSDN 里说,VC 有 3 个预处理常量,分别是 _WIN32,_WIN64,WIN32.这三个常量如何使用呢?看起来简单,其实是很困惑的. 在 Win32 配置下,WIN32 在“项目属性-C/C ...

  8. STM32F10xxx_Keil中添加的预定义宏

    目录 STM32F10xxx_Keil中添加的预定义宏 更新记录 STM32F10xxx_Keil中添加的预定义宏 更新记录 version status description date autho ...

  9. Windows平台编译器相关的几个预定义宏

    WIN32 是在windows.h 中定义的宏,包含winodws.h则定义该宏 _WIN32/_WIN64跟windows平台有关的宏,_WIN32在windows   32位和64位下都有该宏,_ ...

随机推荐

  1. C# Console 运行之后最小化到状态栏

    static void Main(string[] args) { new ConsoleCtrl(); Console.Read(); } class ConsoleCtrl { [DllImpor ...

  2. CentOS 下安装MySQL 默认源为5.1版本

    CentOS——默认为安装5.1版本,如果需要安装5.5版本,需要使用remi源 yum install mysql-server –enablerepo=remi   Ubuntu——默认为安装5. ...

  3. plsql 存储过程 测试

      plsql 存储过程 测试 CreationTime--2018年8月14日09点54分 Author:Marydon 1.找到要运行的存储过程-->选中-->右键-->测试 2 ...

  4. 初步了解“C#反射”

    来源:http://zhidao.baidu.com/link?url=YzuEaWpYMxYV86bAFVmSAGYtXEzkJ_ndMyZ69QuvNJfikwXvlmtP42hAslGFS2uu ...

  5. springmvc编码问题

    web.xml中加入 <filter> <filter-name>encodingFilter</filter-name> <filter-class> ...

  6. HDUOJ---1996汉诺塔VI

    汉诺塔VI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  7. PHP5.3新特性

    1.首先对之前滥用的语法进行了规范 众所周知PHP在语言开发过程中有一个很好的容错性,导致在数组或全局变量中包含字符串不使用引号是可以不报错的,很多业余的开发者因为懒惰而产生的安全问题十分严重,之所以 ...

  8. PC上的番茄工作法软件 Pomodairo 1.9 详细攻略

    http://www.zhantuo.com/archives/673155 番茄钟软件 Pomodairo 1.9: 我觉得这款软件特别好,完全符合番茄工作法的要求. 你可以通过add new 来增 ...

  9. SecureCRT 快捷键总结 设置快捷键

    http://oldboy.blog.51cto.com/2561410/907098 自己整理的一些 查看 Alt + Enter     全屏   菜单 Alt + f + n     克隆会话窗 ...

  10. oracle导表小结

    事件描述:从A主机oracle服务器导出.sql文件到B主机,发现1.导入存在乱码 2.提示USERS表空没有权限(A B主机均为window系统) 1.针对第一点乱码 首先确认系统的默认字符编码GB ...