C23中nullptr_t是否破坏类型双关或指针转换?
关于C23中
nullptr_t与void*联合双关的行为疑问 背景与代码示例
联合类型定义
typedef union { void* vptr; nullptr_t nptr; } pun_intended;
根据C23标准草案n3096的7.21.2章节,nullptr_t与void*兼容,其大小、对齐方式同字符类型指针,nullptr的对象表示与void*空指针值的对象表示一致。
初始化操作
将void*成员初始化为非零值:
pun_intended foo = { .vptr = (void*)42 };
按照C23 6.3.2.3 §4,该整数转指针的转换属于实现定义行为;联合类型双关操作合法;通过字符类型指针检查对象内部表示的行为,在C23 6.3.2.3 §7中是定义良好的。
完整示例代码
#include <stdio.h> #include <inttypes.h> #include <stddef.h> typedef union { void* vptr; nullptr_t nptr; } pun_intended; int main(void) { pun_intended foo = { .vptr = (void*)42 }; printf("Value: %" PRIuPTR "\n", (uintptr_t)foo.vptr); if(foo.nptr != (void*)42) { puts("It does not have value 42."); if(foo.nptr == nullptr) puts("Because it's a nullptr."); else puts("But it's not a nullptr."); unsigned int val = *(unsigned char*)&foo; // 假设小端序 printf("And it has value %d.\n", val); if(foo.vptr != nullptr) { puts("foo.vptr is however not a nullptr."); } } }
不同编译器输出
Clang 16(-std=c2x)输出
Value: 42 It does not have value 42 Because it's a nullptr And it has value 42. foo.vptr is however not a nullptr
GCC 13.2(-std=c2x)输出
Value: 42 It does not have value 42. But it's not a nullptr. And it has value 42. foo.vptr is however not a nullptr.
核心疑问与解答
核心问题
上述原本定义良好或实现定义的操作,在C23中是否变为未定义/未指定行为?若为是,标准中何处有相关说明?还是这些场景未被C23考虑,属于标准缺陷?
解答
整数转
void*的转换:C23 6.3.2.3 §4依然明确,将非零整数转换为指针类型属于实现定义行为,并未变为未定义行为。实现可自行决定是否支持该转换及具体行为逻辑。联合双关访问
nullptr_t成员:- C23仅规定
nullptr的对象表示与void*空指针一致,但未明确非空指针值的对象表示与nullptr_t类型值的对应关系。 - 从两款编译器的差异输出可见,该场景属于未指定行为:标准未统一规定结果,由编译器自行判定非空指针对象表示对应的
nullptr_t值是否为nullptr。
- C23仅规定
通过字符指针检查对象表示:C23 6.3.2.3 §7仍允许通过字符类型指针访问对象的内部表示,该操作始终是定义良好的,这也是两款编译器都能正确输出对象第一个字节值42的原因。
标准是否存在缺陷:
目前C23标准草案仅覆盖了nullptr与void*空指针的对象表示一致性,未明确void*为非空值时联合双关访问nullptr_t成员的行为,导致编译器实现差异,属于标准未明确覆盖的场景,可视为待完善的细节缺陷。
内容的提问来源于stack exchange,提问作者Lundin
相关产品推荐
相关产品推荐

