[TOC]
用Imgui显示中文的时候,最后一个字符偶尔乱码~
描述
- 打印了一下十六进制
int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
{
#ifdef IMGUI_USE_STB_SPRINTF
int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
#else
int w = vsnprintf(buf, buf_size, fmt, args);
#endif
if (buf == NULL)
return w;
// test
if (w == -1)
{
for (int i = 0; i < strlen(fmt); ++i)
{
printf("%2X ", fmt[i]);
}
printf("err(%d) %d\n", errno, buf_size);
}
// test end
if (w == -1 || w >= (int)buf_size)
w = (int)buf_size - 1;
buf[w] = 0;
return w;
}
#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
打印结果,找到一个查编码的网页[4],不错
FFFFFFE6 FFFFFF97 FFFFFFB6 FFFFFFE9 FFFFFF97 FFFFFFB4 FFFFFFE9 FFFFFF80 FFFFFF9F FFFFFFE5 FFFFFFBA FFFFFFA6 FFFFFFEF FFFFFFBC FFFFFF9A err(22) 3073
时:xE6\x97\xB6
间:xE9\x97\xB4
速:\xE9\x80\x9F
度:\xE5\xBA\xA6
中文冒号:\xEF\xBC\x9A
原因
- 看到错误码是22 == EINVAL,就知道原因了。因为调用到vsnprintf的时候,格式化后面没有参数,如下所示:
ImGui.Text("时间速度:");
这就导致ImFormatStringV函数返回了整个buf_size,而Imgui把这整个size都显示到界面上,就GG了
errno
参考[2][3],还有errno.h
// Error codes used in the Secure CRT functions
#ifndef RC_INVOKED
#define _SECURECRT_ERRCODE_VALUES_DEFINED
#define EINVAL 22
#define ERANGE 34
#define EILSEQ 42
#define STRUNCATE 80
#endif
解决
- 方法1:修改ImFormatStringV中vsnprintf返回-1,主要是(errno==EINVAL)的情况,再取源字符串的长度判断一下
if (w == -1 || w >= (int)buf_size)
{
w = strlen(fmt);
w = w < buf_size - 1 ? w : (int)buf_size - 1;
}
看ImGui::TextEx里面其实也做了一层判断,只是再ImFormatStringV的时候走不到而已
void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
ImGuiContext& g = *GImGui;
IM_ASSERT(text != NULL);
const char* text_begin = text;
if (text_end == NULL)
text_end = text + strlen(text); // FIXME-OPT
- 方法2:把buf清0
理论上把g.TempBuffer格式化就可以了,没测试过,不知道有木有影响~
void ImGui::TextV(const char* fmt, va_list args)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
ImGuiContext& g = *GImGui;
const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
TextEx(g.TempBuffer, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
}
- 方法3:使用Imgui.TextUnformatted显示没有参数的文本
参考
[1]vsnprintf、_vsnprintf、_vsnprintf_l、_vsnwprintf、_vsnwprintf_l
[2]vsnprintf
[3]errno
[4]在线编码插叙