读取X11的UTF8_STRING属性是否保证以NULL结尾?及代码正确性疑问
关于X11读取_NET_WM_NAME属性的疑问与解答
代码片段
static Atom _NET_WM_NAME = XInternAtom( display, "_NET_WM_NAME", false ); unsigned char* wm_data = NULL; Atom wm_type; int wm_format; unsigned long wm_nitems, wm_bytes; std::string title; int ret = XGetWindowProperty( display, window, _NET_WM_NAME, 0, 512, false, utf8_string, &wm_type, &wm_format, &wm_nitems, &wm_bytes, &wm_data); if( ret == Success && wm_nitems != 0 && wm_data != NULL ) { title = (const char*)wm_data; // [1] }
疑问
根据规范,_NET_WM_NAME属性为UTF8_STRING类型。上述代码中[1]处假设接收的数据始终以NULL结尾,代码目前可正常运行,但返回的wm_nitems未包含NULL终止符,其值与实际字符串长度一致,因此产生以下疑问:
- 读取UTF8_STRING类型属性是否一定会返回包含NULL终止符的字符串?
- 若确实如此,为何NULL终止符不计入wm_nitems的计数?
- 能否指出规范中对此的相关说明位置?
- 上述读取_NET_WM_NAME属性的代码片段是否正确?
解答
1. 是否一定会返回带NULL终止符的字符串?
不是必须的。EWMH(扩展窗口管理器提示)规范仅规定_NET_WM_NAME的类型为UTF8_STRING,而X11 ICCCM(客户端间通信约定手册)中明确UTF8_STRING是以字节为单位的UTF-8编码序列,不要求自带NULL终止符。只是多数窗口管理器会额外添加一个NULL字节方便C程序处理,但这属于非标准的“贴心行为”,不能依赖。
2. 为何NULL终止符不计入wm_nitems?
wm_nitems是XGetWindowProperty返回的属性原始数据的有效元素数量,对于UTF8_STRING来说,元素就是单个字节。NULL终止符不属于窗口标题的有效内容,只是C风格字符串的约定,因此不会被计入属性的正式长度。窗口管理器额外添加的NULL是给C程序的便利,不属于属性本身的数据部分。
3. 规范中的说明位置
- EWMH规范:
_NET_WM_NAME条目明确其类型为UTF8_STRING,未要求NULL终止。 - X11 ICCCM:UTF8_STRING的定义为“无NULL终止要求的UTF-8字节序列”。
- XGetWindowProperty手册:返回的数据是属性的原始字节,
wm_nitems对应原始数据的元素数(字节数),不会自动添加或统计终止符。
4. 代码是否正确?
不正确,主要有两个问题:
- 依赖非必须的NULL终止符,遇到不添加NULL的窗口管理器会读取到垃圾数据甚至崩溃。
- 未调用
XFree(wm_data)释放内存,会造成内存泄漏。
修正后的代码:
static Atom _NET_WM_NAME = XInternAtom( display, "_NET_WM_NAME", false ); unsigned char* wm_data = NULL; Atom wm_type; int wm_format; unsigned long wm_nitems, wm_bytes; std::string title; int ret = XGetWindowProperty( display, window, _NET_WM_NAME, 0, 512, false, utf8_string, &wm_type, &wm_format, &wm_nitems, &wm_bytes, &wm_data); if( ret == Success && wm_nitems != 0 && wm_data != NULL ) { // 用实际字节数构造字符串,不依赖NULL终止符 title = std::string(reinterpret_cast<const char*>(wm_data), wm_nitems); } // 必须释放XGetWindowProperty返回的内存 if (wm_data != NULL) { XFree(wm_data); }
内容的提问来源于stack exchange,提问作者LoPiTaL
相关产品推荐
相关产品推荐

