向接受QChar*的函数传递void*/const void*的语义合规性问询
关于
util_strchrnul处理void*/const void*的C标准规定解析 一、_Generic匹配的标准规则
_Generic的分支匹配严格遵循实参的实际类型,不会自动触发隐式类型转换。你实现的util_strchrnul宏仅定义了char*和const char*两个匹配分支,当传入void*或const void*时,没有对应的分支能匹配,编译报错完全符合C标准(_Generic自C11起引入)的要求。
二、C23前strchrnul接受void*的原因
C23之前,标准库的strchrnul(POSIX扩展,C标准兼容该用法)通常采用如下原型:
void* strchrnul(const void* s, int c);
C语言允许任何对象指针隐式转换为void*,同时void*也能隐式转换为其他对象指针(C23前规则)。因此你之前的代码:
void *p = "he\0llo"; *strchrnul(p, '\0') = '\0';
能编译通过的逻辑是:
p(void*)隐式转换为const void*传入函数;- 返回的
void*再隐式转换为char*,从而支持解引用赋值。
但你的_Generic实现未处理void*/const void*分支,因此无法兼容这类调用。
三、void*/const void*的返回逻辑是否符合标准
如果要让util_strchrnul支持这两种指针类型,只需在_Generic中新增对应分支:
#define util_strchrnul(s, c) _Generic((s), char *: util_strchrnul_vanilla, const char *: util_strchrnul_const, void *: util_strchrnul_vanilla, const void *: util_strchrnul_const)(s, c)
从标准角度看:
void*匹配后调用util_strchrnul_vanilla(接受char*),本质是显式指定将void*转换为char*,C23前允许隐式转换,C23中需显式转换,但通过_Generic分支绑定的方式是合法的;const void*匹配util_strchrnul_const(接受const char*),属于限定符兼容的指针转换,完全符合C标准规则。
需要注意:这种转换的前提是void*指向的确实是char类型对象,否则会触发未定义行为——这和原生strchrnul的使用要求一致,因为该函数本质是用于处理字符数组的工具。
内容的提问来源于stack exchange,提问作者Madagascar
相关产品推荐
相关产品推荐

