成都网站建设设计

将想法与焦点和您一起共享

C语言通过宏定义实现便捷打印参数值和参数名-创新互联

目录
  • 1、格式化打印变量名和值
  • 2、重定向printf
  • 3、头文件支持

为临安等地区用户提供了全套网页设计制作服务,及临安网站建设行业解决方案。主营业务为成都网站设计、做网站、临安网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!1、格式化打印变量名和值

Python 3.8以上的版本支持f字符串的变量打印功能1,比如:

num = 42
print(f'{num=}')

输出得到:

num=42

这样的方法提高了调试效率。

我觉得这个方法不错,利用C语言的宏定义#var可以将变量转化为字符串,实现类似的效果:

#if LINE_NUMBER
	#define LN printf("(ln: %3d) ", __LINE__)
#else
	#define LN 0
#endif
#define puts(s)    LN + printf("%s\n", s)
#define log_str(x) LN + printf(#x"=\"%s\"\n", x)
#define log_num(x) LN + printf(#x"=%g\n", (float)x)

打印的效果类似如下:

(ln:  7) start!
(ln: 10) s="Hello!"
(ln: 15) n1=1024
(ln: 16) n2=3.14

其中printf函数返回值是int类型,所以可以利用两个printf函数相加,实现在一次printf后再printf一次,通过开关宏定义LINE_NUMBER设置是否打印行号。

如果C语言支持C11标准,支持_Generic关键词,还可以将数字、或字符串用同一个宏定义函数打印2。参考代码如下:

#include#define u8  unsigned char
#define u16 unsigned short
#define u32 unsigned int
#define u64 unsigned long long

#define s8  signed char
#define s16 signed short
#define s32 signed int
#define s64 signed long long

void log_int(const char* name, int value) {printf("%s=%d\n", name, value);
}

void log_float(const char* name, float value) {printf("%s=%g\n", name, value);
}

void log_str(const char* name, void* value) {printf("%s=\"%s\"\n", name, value);
}

#define log(x) _Generic((x)\
	,u8    : log_int\
	,u16   : log_int\
	,u32   : log_int\
	,s8    : log_int\
	,s16   : log_int\
	,s32   : log_int\
	,float : log_float\
	,double: log_float\
	,u8*   : log_str\
	,s8*   : log_str\
	,char* : log_str\
)(#x, x)

void main() {int   n1 = -114;
	float n2 = 5.14;
	char  s1[] = "hello";
	log(n1);
	log(n2);
	log(s1);
}
2、重定向printf

有时候在嵌入式平台上,printf打印需要重定向到串口输出。如果遇到不能使用printf打印,可以使用一种替代的解决方法:

#include#include#include#define PRINT_TO_SCREEN 1
#define PRINT_TO_STRING 1
#define PRINT_TO_FILE   1

#define printf log_print

char  log_buff[0x100000]; // 1MB
char *log_pbuff = log_buff;
int   log_reset = 1;

int log_print(char* format, ...)
{va_list p;
    va_start(p, format);

#if PRINT_TO_SCREEN
    vprintf(format, p);
#endif

#if PRINT_TO_STRING
    vsprintf(log_pbuff, format, p);
    log_pbuff = strchr(log_pbuff, 0);
#endif

#if PRINT_TO_FILE
    FILE *fp = fopen("log.txt", log_reset ? "w+" : "a+");
    log_reset = 0;
    vfprintf(fp, format, p);
    fclose(fp);
#endif

    va_end(p);
    return 0;
}

通过将printf重定向到log_print函数,使用原有的printf就可以可选地将内容打印到屏幕、字符串、和本地文件。

通过初始化全局变量log_reset是否等于1,可以设置每次重启程序前是否清空之前记录文件。

使用方法参考:

printf("k=%d\n", 114);
printf("y=%d\n", 514);

运行结束后再次查看buf,字符串会变得丰富:

"k=114\ny=514\n"

需要注意的是,总打印的字符长度不要超过buf申请的空间长度,例如本示例中申请的0x1000001MB空间大小。

本方法前面的宏定义打印参数名+参数值两者互相不冲突,可以同时使用。

3、头文件支持

我将代码整理成了头文件的形式,现在可以通过添加头文件,将调试函数加入代码,在代码一开头加入:

#include "log.h"

就可以使用头文件里面的函数了。文件下载地址:

https://download.csdn.net/download/weixin_39804265/87241255


  1. https://docs.python.org/zh-cn/3.8/whatsnew/3.8.html#f-strings-support-for-self-documenting-expressions-and-debugging ↩︎

  2. https://www.zhihu.com/question/555675067/answer/2691305812 ↩︎

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


分享标题:C语言通过宏定义实现便捷打印参数值和参数名-创新互联
本文链接:http://chengdu.cdxwcx.cn/article/pjops.html