省略号 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
你走运了。
同nullptr
you get void*
,不过再看上面。
我有函数使用省略号获取一个变量和以 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 withT
, 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
, orunsigned char
).
(这与实际的 C11 措辞非常接近;请记住,va_arg
是由 C 而不是 C++ 定义的。)
现在,C11 对 "compatible types" 的定义由 another cppreference 总结,它告诉我们,为了使您的 NULL
具有与 Serializable*
兼容的类型,指针对象NULL
的类型必须与 Serializable
.
现在,NULL
has an implementation-defined type 所以你不知道它是什么,但它肯定不会与 Serializable
兼容,除非它只是 [=13] 的类型别名=] 或 int
你走运了。
同nullptr
you get void*
,不过再看上面。