显然,当没有参数(通过std::nullptr_t
)传递时,void *
参数被转换为类型为...
的空指针(N3337的第5.2.2 / 7节)。这意味着要正确传递空char *
指针,例如,仍需要强制转换:
some_variadic_function(“a”,“b”,“c”,(const char *)std :: nullptr);
因为无法保证null void *
具有与null char *
相同的位模式。正确的吗?
这也意味着std::nullptr
在这种情况下0
没有优势,除非为了清晰起见。
答案 0 :(得分:7)
你问:
因为无法保证null
void *
具有与nullchar *
相同的位模式。正确的吗?
嗯,实际上,这种保证确实存在,Deduplicator的答案已经显示了标准要求的地方。但这与你的问题无关。
将void *
传递给可变参数函数,并使用va_arg
作为char *
访问它,特别允许作为特殊例外。
C ++ 11:
18.10其他运行时支持[support.runtime]
1个标题
<csetjmp>
(非本地跳转),<csignal>
(信号处理),<cstdalign>
(对齐),<cstdarg>
(可变参数),<cstdbool>
(__bool_true_false_are_defined
)。 (运行环境getenv()
,system()
)和<ctime>
(系统时钟clock()
,time()
)提供了与C代码的进一步兼容性。2这些标头的内容与标准C库标题
<setjmp.h>
,<signal.h>
,<stdalign.h>
,<stdarg.h>
,<stdbool.h>
,{{ 1}}和<stdlib.h>
分别具有以下内容 变化:[......没有关于
<time.h>
]
C99:
7.15.1.1
va_arg
宏[...]如果没有实际的下一个参数,或者 type 与实际的下一个参数的类型不兼容(根据默认参数促销提升),行为未定义,除以下情况外:
- 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且该值可在两种类型中表示;
- 一种类型是指向void的指针,另一种是指向字符类型的指针。
但是,这确实意味着在va_arg
和T1
两种类型具有相同的表示和对齐要求的其他情况下,如果将T2
传递给可变参数函数,则行为未定义,它被检索为T1
。
这样做的一个示例:允许传递T2
并以(void *) 0
方式访问它,传递char *
并允许(void *) 0
访问它,但是传递{{} 1}}并以unsigned char *
访问它是不允许。如果编译器能够内联对可变参数函数的调用,并根据标准的严格要求进行优化,那么这种不匹配可能会严重破坏。
这也意味着
(char *) 0
在这种情况下unsigned char *
没有优势,除非为了清晰起见。
我肯定不使用std::nullptr
而不进行投射,即使在这一特殊情况下它是有效的。很难看出它是有效的。如果无论如何都包含一个强制转换,0
就像空指针值一样清晰。
答案 1 :(得分:2)
你错了。少数保证之一是char*
具有与相应void*
相同的大小和表示。
3.9.2复合类型§4
指向cv-qualified(3.9.3)或cv-unqualified void的指针可用于指向未知类型的对象。 这样的指针应该能够保存任何对象指针。 cv
void*
类型的对象应具有相同的对象 表示和对齐要求为cvchar*
。
编辑:看起来this answer by hvd更好,显示了一些特定于问题的可变函数部分的陷阱。