You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

向接受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';

能编译通过的逻辑是:

  1. p(void*)隐式转换为const void*传入函数;
  2. 返回的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:17:07