【问题标题】:Ellipsis NULL, nullptr and undefined behaviour省略号 NULL、nullptr 和未定义的行为
【发布时间】:2019-02-04 11:35:59
【问题描述】:

我有一个函数使用省略号来获取一个变量和 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);

【问题讨论】:

  • 能否改正标题中的错字?
  • 是的,只需edit您的帖子。
  • 为什么不使用可变参数模板来代替这种非常糟糕的 C 风格代码?
  • @MatthieuBrucher “我知道可变长度模板参数列表。它是关于遗留代码的。” - OP
  • @LightnessRacesinOrbit 好吧,这取决于,我不是为了现代而写这样的东西。我会先写测试,但如果你在测试时不考虑更改代码,那么我可能会解雇你。

标签: c++ null variadic-functions nullptr


【解决方案1】:

不,我不这么认为。

引用cppreference.com on va_arg:

如果ap(升级后)中下一个参数的类型与T不兼容,则行为未定义,除非:

  • 一种是有符号整数类型,另一种是对应的无符号整数类型,值在两种类型中都可以表示;或
  • 一种是指向void的指针,另一种是指向字符类型(charsigned charunsigned char)的指针。

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

现在,C11 对“兼容类型”的定义总结为 another cppreference,它告诉我们,要使您的 NULL 具有与 Serializable* 兼容的类型,NULL 的指针类型必须兼容Serializable

现在,NULL has an implementation-defined type,所以你不知道它是什么,但它肯定不会与 Serializable 兼容,除非它只是 voidint 的类型别名,而你祝你好运。

nullptryou get void*,但后来又见上文。

【讨论】:

  • 这是关于 C 意义上的“兼容性”,我认为。如果I read correctlyvoid*(作为额外省略号参数传递时为what nullptr_t is converted to)与Serializable* 不兼容。
  • 促销不是隐式转换吗?
  • 我们可以类比printf("%p", x)。 GCC 允许xvoid *nullptr_t,但对任何其他指针类型和NULL 发出警告。但我同意警告可能会被打破......
  • @StoryTeller 同意。正在研究:)(有点晚了:P)
  • @MartinFehrs 促销是所有隐式转换的有限子集。也就是说,您可以将它们归类为隐式转换,但这并不意味着“提升”需要任何可能的隐式转换。促销基本上只是为了让ints 更大
猜你喜欢
  • 2019-06-28
  • 2019-09-01
  • 1970-01-01
  • 2016-10-23
  • 2018-02-21
  • 1970-01-01
  • 2011-11-04
  • 2022-07-07
  • 1970-01-01
相关资源
最近更新 更多