省略号 NULL、nullptr 和未定义的行为

Ellipsis NULL, nullptr and undefined behaviour

我有函数使用省略号获取一个变量和以 NULL 结尾的指针参数列表。我知道可变长度模板参数列表。它是关于遗留代码的。以下两个调用是否会导致未定义的行为,因为终止符被 va_arg 解释为 Serializable*?这两个调用有什么区别?

void serialize(Serializable* first, ...) {
    va_list vl;

    va_start(vl, first);

    while(1)
    {
        Serializable* arg = va_arg(vl, Serializable*);

        if(arg == NULL)
            break;

        /* serialize arg here */
    }
}

serialize(obj1, obj2, obj3, NULL);
serialize(obj1, obj2, obj3, nullptr);

不,我不这么认为。

引用 cppreference.com on va_arg:

If the type of the next argument in ap (after promotions) is not compatible with T, the behavior is undefined, unless:

  • one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types; or
  • one type is pointer to void and the other is a pointer to a character type (char, signed char, or unsigned char).

(这与实际的 C11 措辞非常接近;请记住,va_arg 是由 C 而不是 C++ 定义的。)

现在,C11 对 "compatible types" 的定义由 another cppreference 总结,它告诉我们,为了使您的 NULL 具有与 Serializable* 兼容的类型,指针对象NULL 的类型必须与 Serializable.

兼容

现在,NULL has an implementation-defined type 所以你不知道它是什么,但它肯定不会与 Serializable 兼容,除非它只是 [=13] 的类型别名=] 或 int 你走运了。

nullptryou get void*,不过再看上面。