考虑一下这个联盟:

typedef union
{
  void*      vptr;
  nullptr_t  nptr;
} pun_intended;

nullptr_t应该与void*1)兼容.好的,那么如果我们将void*初始化为某个非零值呢?

pun_intended foo = { .vptr = (void*)42 }; 
  • 根据C23 6.3.2.3第4节,此转换被认为是合法的(隐含定义的),或者至少在引入nullptr_t之前是合法的.
  • 那么unions 式的双关语呢?同样被认为是合法的.
  • 如何使用字符类型指针判断C中任何类型的内部表示形式,该指针在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; // little endian assumption here
    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中被考虑--这是一个缺陷?


1)来源:C23 n3096草案7.21.2

nullptr_t的大小和对齐方式与指向字符类型的指针相同.值nullptr的对象表示与类型void*的空指针值的对象表示相同.

推荐答案

好的,那么如果我们将void*初始化为某个非零值呢?

C 2023 N3096 7.21.2 3明确回答了这个问题.在告诉我们nullptr_t类型中的nullptr值的表示与void *类型中的空指针值的表示相同之后,它告诉我们如果nullptr_t对象中有不同的字节值序列会发生什么:

…如果对象表示形式不同,则行为未定义.

C++相关问答推荐

CC crate 示例不会与C函数链接

C strlen on char array

与unions 的未定义行为

来自stdarg.h的c中的va_args无法正常工作<>

在#include中使用C宏变量

正在try 将文件/文件夹名从目录 struct 存储到链接列表

将uintptr_t添加到指针是否对称?

在为hashmap创建加载器时,我的存储桶指向它自己

判断X宏的空性

如何确保在C程序中将包含uft8字符的字符串正确写入MySQL?

有什么方法可以将字符串与我们 Select 的子字符串分开吗?喜欢:SIN(LOG(10))

为什么函数是按照定义的顺序执行的,而不是按照从avr-c中的int main()调用的顺序执行的?

通过k&;r语法的c声明无效

如何在不读取整个字符串的情况下删除UTF8字符串的尾随空格以提高性能?

有没有办法减少C语言中线程的堆大小?

赋值两侧的后置增量,字符指针

当我将偏移量更改为任何非零值时,C中的mmap共享内存出现无效参数错误

如何打印循环调度问题的时间表

将数组返回到链表

如何转义包含指令中的字符?