如何解决直接启动应用程序时,控制台中的 C++ 彩色文本不显示
我已经为我用 C++ 编写的应用程序实现了我自己的 Logging 类。我使用这种为文本着色的方式 (https://stackoverflow.com/a/54062826/12873837) 实现了 Logging 类。如果我使用调试器在 Visual Studio 中启动我的程序,它确实工作得很好,但如果我直接启动我的应用程序就不行。 ANSI 转义颜色代码不是彩色文本,而是在我的实际控制台输出之前直接打印出来。任何想法为什么会发生这种情况?
这个截图是输出,如果我直接启动应用程序。
解决方法
感谢@1201ProgramAlarm,我终于在这里找到了解决方案:https://stackoverflow.com/a/63426872/12873837
这对我来说非常好:)
,也许这段代码很有用
#include <iostream>
#include <set>
#include <string>
#include <locale>
// WINDOWS
#if (_WIN32)
#include <Windows.h>
#include <conio.h>
#define WINDOWS_PLATFORM 1
#define DLLCALL STDCALL
#define DLLIMPORT _declspec(dllimport)
#define DLLEXPORT _declspec(dllexport)
#define DLLPRIVATE
#define NOMINMAX
//EMSCRIPTEN
#elif defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
#include <unistd.h>
#include <termios.h>
#define EMSCRIPTEN_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
// LINUX - Ubuntu,Fedora,Centos,Debian,RedHat
#elif (__LINUX__ || __gnu_linux__ || __linux__ || __linux || linux)
#define LINUX_PLATFORM 1
#include <unistd.h>
#include <termios.h>
#define DLLCALL CDECL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#define CoTaskMemAlloc(p) malloc(p)
#define CoTaskMemFree(p) free(p)
//ANDROID
#elif (__ANDROID__ || ANDROID)
#define ANDROID_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
//MACOS
#elif defined(__APPLE__)
#include <unistd.h>
#include <termios.h>
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
#define IOS_SIMULATOR_PLATFORM 1
#elif TARGET_OS_IPHONE
#define IOS_PLATFORM 1
#elif TARGET_OS_MAC
#define MACOS_PLATFORM 1
#else
#endif
#endif
typedef std::string String;
typedef std::wstring WString;
#define EMPTY_STRING u8""s
#define EMPTY_WSTRING L""s
using namespace std::literals::string_literals;
class Strings
{
public:
static String WideStringToString(const WString& wstr)
{
if (wstr.empty())
{
return String();
}
size_t pos;
size_t begin = 0;
String ret;
#if WINDOWS_PLATFORM
int size;
pos = wstr.find(static_cast<wchar_t>(0),begin);
while (pos != WString::npos && begin < wstr.length())
{
WString segment = WString(&wstr[begin],pos - begin);
size = WideCharToMultiByte(CP_UTF8,WC_ERR_INVALID_CHARS,&segment[0],segment.size(),NULL,NULL);
String converted = String(size,0);
WideCharToMultiByte(CP_UTF8,&converted[0],converted.size(),NULL);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = wstr.find(static_cast<wchar_t>(0),begin);
}
if (begin <= wstr.length())
{
WString segment = WString(&wstr[begin],wstr.length() - begin);
size = WideCharToMultiByte(CP_UTF8,NULL);
ret.append(converted);
}
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
size_t size;
pos = wstr.find(static_cast<wchar_t>(0),pos - begin);
size = wcstombs(nullptr,segment.c_str(),0);
String converted = String(size,0);
wcstombs(&converted[0],converted.size());
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = wstr.find(static_cast<wchar_t>(0),wstr.length() - begin);
size = wcstombs(nullptr,converted.size());
ret.append(converted);
}
#else
static_assert(false,"Unknown Platform");
#endif
return ret;
}
static WString StringToWideString(const String& str)
{
if (str.empty())
{
return WString();
}
size_t pos;
size_t begin = 0;
WString ret;
#ifdef WINDOWS_PLATFORM
int size = 0;
pos = str.find(static_cast<char>(0),begin);
while (pos != std::string::npos) {
std::string segment = std::string(&str[begin],pos - begin);
std::wstring converted = std::wstring(segment.size() + 1,0);
size = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,converted.length());
converted.resize(size);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = str.find(static_cast<char>(0),begin);
}
if (begin < str.length()) {
std::string segment = std::string(&str[begin],str.length() - begin);
std::wstring converted = std::wstring(segment.size() + 1,converted.length());
converted.resize(size);
ret.append(converted);
}
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
size_t size;
pos = str.find(static_cast<char>(0),begin);
while (pos != String::npos)
{
String segment = String(&str[begin],pos - begin);
WString converted = WString(segment.size(),0);
size = mbstowcs(&converted[0],converted.size());
converted.resize(size);
ret.append(converted);
ret.append({ 0 });
begin = pos + 1;
pos = str.find(static_cast<char>(0),begin);
}
if (begin < str.length())
{
String segment = String(&str[begin],str.length() - begin);
WString converted = WString(segment.size(),converted.size());
converted.resize(size);
ret.append(converted);
}
#else
static_assert(false,"Unknown Platform");
#endif
return ret;
}
};
enum class ConsoleTextStyle
{
DEFAULT = 0,BOLD = 1,FAINT = 2,ITALIC = 3,UNDERLINE = 4,SLOW_BLINK = 5,RAPID_BLINK = 6,REVERSE = 7,};
enum class ConsoleForeground
{
DEFAULT = 39,BLACK = 30,DARK_RED = 31,DARK_GREEN = 32,DARK_YELLOW = 33,DARK_BLUE = 34,DARK_MAGENTA = 35,DARK_CYAN = 36,GRAY = 37,DARK_GRAY = 90,RED = 91,GREEN = 92,YELLOW = 93,BLUE = 94,MAGENTA = 95,CYAN = 96,WHITE = 97
};
enum class ConsoleBackground
{
DEFAULT = 49,BLACK = 40,DARK_RED = 41,DARK_GREEN = 42,DARK_YELLOW = 43,DARK_BLUE = 44,DARK_MAGENTA = 45,DARK_CYAN = 46,GRAY = 47,DARK_GRAY = 100,RED = 101,GREEN = 102,YELLOW = 103,BLUE = 104,MAGENTA = 105,CYAN = 106,WHITE = 107
};
class Console
{
private:
static void EnableVirtualTermimalProcessing()
{
#if defined WINDOWS_PLATFORM
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut,&dwMode);
if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
{
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut,dwMode);
}
#endif
}
static void ResetTerminalFormat()
{
std::cout << u8"\033[0m";
}
static void SetVirtualTerminalFormat(ConsoleForeground foreground,ConsoleBackground background,std::set<ConsoleTextStyle> styles)
{
String format = u8"\033[";
format.append(std::to_string(static_cast<int>(foreground)));
format.append(u8";");
format.append(std::to_string(static_cast<int>(background)));
if (styles.size() > 0)
{
for (auto it = styles.begin(); it != styles.end(); ++it)
{
format.append(u8";");
format.append(std::to_string(static_cast<int>(*it)));
}
}
format.append(u8"m");
std::cout << format;
}
public:
static void Clear()
{
#ifdef WINDOWS_PLATFORM
std::system(u8"cls");
#elif LINUX_PLATFORM || defined MACOS_PLATFORM
std::system(u8"clear");
#elif EMSCRIPTEN_PLATFORM
emscripten::val::global()["console"].call<void>(u8"clear");
#else
static_assert(false,"Unknown Platform");
#endif
}
static void Write(const String& s,ConsoleForeground foreground = ConsoleForeground::DEFAULT,ConsoleBackground background = ConsoleBackground::DEFAULT,std::set<ConsoleTextStyle> styles = {})
{
#ifndef EMSCRIPTEN_PLATFORM
EnableVirtualTermimalProcessing();
SetVirtualTerminalFormat(foreground,background,styles);
#endif
String str = s;
#ifdef WINDOWS_PLATFORM
WString unicode = Strings::StringToWideString(str);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),unicode.c_str(),static_cast<DWORD>(unicode.length()),nullptr,nullptr);
#elif defined LINUX_PLATFORM || defined MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
std::cout << str;
#else
static_assert(false,"Unknown Platform");
#endif
#ifndef EMSCRIPTEN_PLATFORM
ResetTerminalFormat();
#endif
}
static void WriteLine(const String& s,std::set<ConsoleTextStyle> styles = {})
{
Write(s,foreground,styles);
std::cout << std::endl;
}
static void Write(const WString& s,styles);
#endif
WString str = s;
#ifdef WINDOWS_PLATFORM
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),str.c_str(),static_cast<DWORD>(str.length()),nullptr);
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
std::cout << Strings::WideStringToString(str);
#else
static_assert(false,"Unknown Platform");
#endif
#ifndef EMSCRIPTEN_PLATFORM
ResetTerminalFormat();
#endif
}
static void WriteLine(const WString& s,styles);
std::cout << std::endl;
}
static void WriteLine()
{
std::cout << std::endl;
}
static void Pause()
{
char c;
do
{
c = getchar();
std::cout << "Press Key " << std::endl;
} while (c != 64);
std::cout << "KeyPressed" << std::endl;
}
static int PauseAny(bool printWhenPressed = false,std::set<ConsoleTextStyle> styles = {})
{
int ch;
#ifdef WINDOWS_PLATFORM
ch = _getch();
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
struct termios oldt,newt;
tcgetattr(STDIN_FILENO,&oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO,TCSANOW,&newt);
ch = getchar();
tcsetattr(STDIN_FILENO,&oldt);
#else
static_assert(false,"Unknown Platform");
#endif
if (printWhenPressed)
{
Console::Write(String(1,ch),styles);
}
return ch;
}
};
int main()
{
std::locale::global(std::locale(u8"en_US.UTF8"));
auto str = u8"?\0Hello\0?123456789也不是可运行的程序123456789日本"s;//
WString wstr = L"?\0Hello\0?123456789也不是可运行的程序123456789日本"s;
WString wstrResult = Strings::StringToWideString(str);
String strResult = Strings::WideStringToString(wstr);
bool equals1 = wstr == wstrResult;
bool equals2 = str == strResult;
Console::WriteLine(u8"█ Converted Strings printed with Console::WriteLine"s,ConsoleForeground::GREEN);
Console::WriteLine(wstrResult,ConsoleForeground::BLUE);
Console::WriteLine(strResult,ConsoleForeground::BLUE);
Console::WriteLine(u8"█ Converted Strings printed with std::cout/std::wcout"s,ConsoleForeground::GREEN);
std::cout << strResult << std::endl;
std::wcout << wstrResult << std::endl;
Console::WriteLine();
Console::WriteLine(u8"Press any key to exit"s,ConsoleForeground::DARK_GRAY);
Console::PauseAny();
}
输出
在 repl.it 中使用 clang Linux 上的默认编码是 UTF-8。
使用 Visual C++ 编译器 和新的 Windows terminal。 Windows 上的默认编码是 UTF-16。当我们有 2 个 wchar_t 单元(代理对)的 unicode 字符时,问题就存在了,经典控制台可以打印一个 wchar_t 单元的字符。新的 Windows 终端可以处理这个问题。在这个例子中检查狗有 2 个 wchar_t 单位不能在经典控制台中正常打印,但在 Windows 终端中可以。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。