一、前言

在后台程序运行出问题时,需要查看详尽的日志,C语言提供记录日志触发点文件名、行号、函数名的方法,关键是利用C99新增的预处理标识符__VA_ARGS__;先介绍几个编译器内置的宏定义,这些宏定义不仅可以帮助我们完成跨平台的源码编写,灵活使用也可以巧妙地帮我们输出非常有用的调试信息。

二、ANSI C标准宏

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

__FILE__ //在源文件中插入当前源文件名

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

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

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

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

_WIN32//在程序运行在windows系统上被定义位1

linux //在程序运行在linux系统上被定义位1

__x86_64__ //在程序运行在64位系统上被定义位1

__i386__ //在程序运行在32位系统上被定义位1

__VA_ARGS__//是一个可变参数的宏,这个可宏是新的C99规范中新增的,//目前似乎gcc和VC6.0之后的都支持(VC6.0的编译器不支持)。//宏前面加上##的作用在于,可以接受参数为0个或者多个

三、实例

宏实例:

#include

intmain()

{

printf("__func__:%s\n", __func__);

printf("__FILE__:%s\n", __FILE__);

printf("__DATE__:%s\n", __DATE__);

printf("__TIME__:%s\n", __TIME__);

printf("__LINE__:%d\n", __LINE__);return 0;

}

宏实例程序输出如下:

__func__:main

__FILE__:main.c

__DATE__:Sep14 2019__TIME__:14:26:36__LINE__:9

四、#和##运算符

其中#和##运算符的功能有所不同,在这里也做一定的介绍

1. #用来把参数转换成字符串

实例1:

#define P(A) printf("%s:%d\n", #A, A);

intmain()

{int a = 1, b = 2;

P(a);

P(b);

P(a+b);return 0;

}

实例1程序输出如下:

a:1b:2a+b:3

实例2:

#define SQUARE(x) printf("The square of "#x" is %d.\n", ((x)*(x)))

intmain()

{

SQUARE(8);return 0;

}

实例2程序输出如下:

The square of 8 is 64

2. ##运算符可以用于宏函数的替换部分

##就是个粘合剂,将前后两部分粘合起来,也就是有“组成变量名”的意思。特别要和#运算符的功能区分开来,#是连接字符串,而##是连接变量名。

但是“##”不能随意粘合任意字符,必须是合法的C语言标示符。在单一的宏定义中,最多可以出现一次“#”或“##”预处理操作符。如果没有指定与“#”或“##”预处理操作符相关的计算次序,则会产生问题。为避免该问题,在单一的宏定义中只能使用其中一种操作符(即,一份“#”或一个“##”,或都不用)。除非非常有必要,否则尽量不要使用“#”和“##”。

实例程序:

#include

#define XNAME(n) SYSTEM_ ## n

intmain()

{int SYSTEM_ = 0,

SYSTEM_OPEN= 1,

SYSTEM_WRITE= 2,

SYSTEM_CLOSE= 3;

printf("%d\n", XNAME());

printf("%d\n", XNAME(OPEN));

printf("%d\n", XNAME(WRITE));

printf("%d\n", XNAME(CLOSE));return 0;

}

实例程序输出:

0

1

2

3

此外,__VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。

##__VA_ARGS__ 宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的逗号去掉的作用,否则会编译出错,相当于能够接受0个及以上的参数。

##__VA_ARGS__的实例:

#define my_print1(fmt,...) printf(fmt, __VA_ARGS__)my_print1("iiijjj\n") //错误打印

my_print1("i=%d,j=%d\n",i,j) //正确打印

#define my_print2(fmt,...) printf(fmt, ##__VA_ARGS__)my_print2("iiijjj\n") //正确打印

my_print2("i=%d,j=%d\n",i,j) //正确打印

linux c 宏 文件名,C语言标准宏获取文件名、行号、函数名的方法以及#和##的用法...相关推荐

  1. Excel宏 取得sheet中最后一行的行号

    近日用到Excel宏,需要取得最后一行的行号,从网上找了找,方法很多,以下这个方法出自CSDN论坛帖子, 方法很简单,而且可以正常统计隐藏行(这个是关键!) n = ActiveSheet.UsedR ...

  2. 熟悉VBA 但是不熟悉 xlwings 怎么办,可以调用 api 操作,如 xlwings 取消自动换行,xlwings选中某一列,xlwings获取最大行号,行标,最大列号,列标等等

    熟悉VBA 但是不熟悉 xlwings 怎么办,可以调用 api 操作,如 xlwings 取消自动换行,xlwings选中某一列,xlwings获取最大行号,行标,最大列号,列标等等 个人常用代码如 ...

  3. python中使用sys模板和logging模块获取行号和函数名的方法

    From: http://www.jb51.net/article/49026.htm 这篇文章主要介绍了python中使用sys模板和logging模块获取行号和函数名的方法,需要的朋友可以参考下 ...

  4. python 获取方法名_python 动态获取当前运行的类名和函数名的方法

    一.使用内置方法和修饰器方法获取类名.函数名 python中获取函数名的情况分为内部.外部,从外部的情况好获取,使用指向函数的对象,然后用__name__属性 复制代码代码如下: def a():pa ...

  5. python获取代码当前行数_Python实验室一段日志代码,获取当前调用的函数名和行号...

    代码如下: #............. class CrawlerLog(object): def __init__(self, logName=None): #............ self. ...

  6. python获取类函数的变量-python 动态获取当前运行的类名和函数名的方法

    一.使用内置方法和修饰器方法获取类名.函数名 python中获取函数名的情况分为内部.外部,从外部的情况好获取,使用指向函数的对象,然后用__name__属性 复制代码 代码如下: def a():p ...

  7. linux只提取前两个目录名,Linux技巧:介绍从目录路径获取文件名和目录前缀的方法...

    使用 dirname 命令获取路径名的目录部分 在 Linux 中,可以使用 dirname 命令获取路径名的目录部分,不包含路径名最后的文件名. 查看 man dirname 的说明如下: dirn ...

  8. elupload获取文件名与路径_Uipath获取文件名,路径,扩展名等操作

    Uipath获取文件名,路径,扩展名等操作 东京IT青年前线​www.rpatokyo.com 使用Assign Activity,声明一个字符串变量为str 获取文件路径代码 System.IO.P ...

  9. python获取代码行号

    获取行号: def get_file(): print("文件名 :",__file__,sys._getframe().f_lineno) print("函数名: &q ...

  10. Linux之Less命令跳转到特定的行号

    本文翻译自:Going to a specific line number using Less in Unix I have a file that has around million lines ...

最新文章

  1. android 虚拟设备的用法
  2. 获得 bootstrapTable行号index
  3. python编程头文件_python头文件怎么写
  4. STL源码学习(一)迭代器概念与traits编程技法
  5. 泥塑课c语言,【C】泥塑课(From http://www.jisuanke.com/)
  6. c语言如何将一个二维数组全为零_从零开始如何用python处理数据
  7. Jarvis Oj Pwn 学习笔记-level0
  8. python多级菜单_python练习题:多级菜单(dict练习)
  9. 站群优化及优化技巧解析
  10. 红宝书新日本语能力考试N1~N5全套资料PDF分享 ​​
  11. FastFDS--文件服务系统
  12. Docker部署应用案例
  13. CSR867x — CSR蓝牙开发调试经验
  14. MTK6577+Android4.0之增加重启功能
  15. 通过session实现通用爬虫--爬取到开心网账户的首页界面
  16. 【离散数学】 MIT 6.042J 笔记 - Lecture 1 Introductions and Proofs
  17. 我喜欢用计算机300,我喜欢的人_作文300字_小学四年级作文_第一范文网
  18. Arduino ESP8266/ESP32读取和改写MAC
  19. 梦想经不起等待 -- 美文转载
  20. 台式计算机如何拆硬盘,机械硬盘怎么拆开?台式机3.5英寸机械硬盘拆卸方法图文教程...

热门文章

  1. 又是一岁,又是一年,又是新的开端【我与51CTO的故事】
  2. 第二季-专题18-网卡搭建新通道
  3. C++基础——类继承中方法重载
  4. 云账房签约葡萄城,开启 “在线Excel+智能财税” 时代
  5. CentOS6.5安装python3.7
  6. 使用源代码编译安装基于LAMP的网站架构
  7. 【Foreign】字符串匹配 [KMP]
  8. 格式化一个文件的大小(size),或者说是格式化一个app的大小(size)
  9. Ubuntu Desktop 变为 Ubuntu Server 服务器版的方法
  10. ASP.NET 首页性能的4大做法