0
点赞
收藏
分享

微信扫一扫

Windows中使用C语言实现打印彩色文字到命令行窗口

夏天的枫_ 2022-04-16 阅读 88
c语言

本文记录的是在Windows中使用C语言自定义一个可以打印彩色文字的printf函数,函数原型如下:

int colorful_printf(WORD color, const char* format, ...);

形参color接收设定的颜色,形参format是printf函数的格式字符串,后面的不确定个数的参数是printf函数的格式输出符对应的待打印项。也就是将传给printf函数的实参原封不动的传过来,再按照参数color指定的颜色进行打印。

要实现这个功能,需要预先掌握如下几方面的知识:

1、在Windows中,实现彩色打印用的是Windows的API函数SetConsoleTextAttribute,这部分知识请参考:

https://baike.baidu.com/item/SetConsoleTextAttribute/570121?fr=aladdin

https://baike.baidu.com/item/GetStdHandle/6909878?fr=aladdin

https://www.jb51.net/article/207562.htm

2、不确定个数的参数的处理,需要使用va_list,这部分知识请参考:

https://baike.baidu.com/item/va_list/8573665?fr=aladdin

https://blog.csdn.net/ZKR_HN/article/details/99558135

3、vsprintf函数,这部分知识请参考:

https://www.runoob.com/cprogramming/c-function-vsprintf.html

掌握了以上的知识后,就可以动手实现我们的函数了。比较简单,直接上代码

#pragma warning(disable:4996)
#include <Windows.h>
#include <stdio.h>
#include <stdarg.h>
#define BLUE (FOREGROUND_INTENSITY | FOREGROUND_BLUE)
#define GREEN (FOREGROUND_INTENSITY | FOREGROUND_GREEN)
#define RED (FOREGROUND_INTENSITY | FOREGROUND_RED)
#define CYAN (FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN)
#define PURPLE (FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_RED)
#define YELLOW (FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED)
#define WHITEBGBLACKFONT ((BACKGROUND_INTENSITY | (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)) | (FOREGROUND_INTENSITY | !(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)))
#define DEFAULT (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)

int main(void)
{
	int colorful_printf(WORD color, const char* format, ...);

	colorful_printf(RED, "%d年北京冬奥会的口号是:%s\n", 2022, "一起向未来!");

	colorful_printf(GREEN, "%d年北京冬奥会的口号是:%s\n", 2022, "一起向未来!");

	colorful_printf(BLUE, "%d年北京冬奥会的口号是:%s\n", 2022, "一起向未来!");

	colorful_printf(CYAN, "%d年北京冬奥会的口号是:%s\n", 2022, "一起向未来!");

	colorful_printf(PURPLE, "%d年北京冬奥会的口号是:%s\n", 2022, "一起向未来!");

	colorful_printf(YELLOW, "%d年北京冬奥会的口号是:%s\n", 2022, "一起向未来!");

	colorful_printf(WHITEBGBLACKFONT, "%d年北京冬奥会的口号是:%s\n", 2022, "一起向未来!");

	return 0;
}

/// <summary>
/// 彩色打印
/// </summary>
/// <param name="color">预期的颜色</param>
/// <param name="format">要打印的格式化字符串</param>
/// <param name="">格式化输出的变量</param>
/// <returns>打印的字符个数(单个汉字或中文标点算两个字符)</returns>
int colorful_printf(WORD color, const char* format, ...)
{
	char str[256];// 要输出的字符串
	va_list ap;// 指向参数的指针
	va_start(ap, format);// 初始化指向参数的指针
	HANDLE consolehwnd = GetStdHandle(STD_OUTPUT_HANDLE);// 输出窗口的句柄
	SetConsoleTextAttribute(consolehwnd, color);// 改为使用预期的颜色输出
	// 按预期的颜色输出
	int ret = vsprintf(str, format, ap);
	printf("%s", str);
	SetConsoleTextAttribute(consolehwnd, DEFAULT);// 恢复默认效果
	va_end(ap);// 结束可变参数的获取

	return ret;
}

打印的效果:

这里记录几个技术要点:

1、要输出的字符串放在字符数组str中,一定要确保数组的长度足以容纳要打印的字符串,否则打印的时候会崩溃。

2、在这里我自定义了一些宏,全部使用了高亮效果,颜色组合的结果是百度查的,如果不够准确还请见谅。宏定义写的比较复杂,实际上完全可以用实际的数值来定义。比如宏DEFAULT,是命令行窗口的默认输出效果,完全可以写成:

#define DEFAULT     0x0007

3、colorful_printf函数的返回值实际上就是vsprintf函数的返回值,表示打印的字符的个数。一个汉字或中文标点算两个字符。

4、在单线程程序中,不会有什么问题。在多线程程序中,如果线程A使用colorful_printf函数进行输出,在内部调用SetConsoleTextAttribute()设置颜色之后,如果线程B恰好在此时进行打印,就会按照线程A中设置的颜色来打印了,这可能不是我们想要的效果。用这个程序无法完全规避这个问题,因为不同的线程都是往一个窗口(就是SetConsoleTextAttribute()的参数hConsoleOutput标识的窗口)中打印。因此只能尽可能地缩短带颜色打印的时间,就是说,调用SetConsoleTextAttribute()设置颜色之后,马上调用vsprintf()和printf()打印,然后再马上调用SetConsoleTextAttribute()恢复为默认效果。如果哪位大神知道适用于多线程,严格区分不同线程的打印颜色的方案,也欢迎指教。

举报

相关推荐

0 条评论