Printf如何知道一个字符串的字符数据的地址?
考虑此代码片段:
struct My {
operator const char*()const{ return "my"; }
} my;
CStringA s( "aha" );
printf("%s %s", s, my );
// another variadic function to get rid of comments about printf :)
void foo( int i, ... ) {
va_list vars;
va_start(vars, i);
for( const char* p = va_arg(vars,const char*)
; p != NULL
; p=va_arg(vars,const char*) )
{
std::cout << p << std::endl;
}
va_end(vars);
}
foo( 1, s, my );
这段代码产生了"直观"的输出"啊哈"。但我不知道这是怎么回事:
- 如果变量函数调用被转换为推送参数的指针,则printf将收到一个被解释为
const char*
的 - 如果变量函数调用正在对它调用
operator (const char*)
,为什么它不为我自己的类调用?
CStringA*
有人能解释一下吗?
编辑:添加了一个虚拟变量函数,该函数将其参数视为const char*
s。请注意,当它到达my
参数时,它甚至会崩溃...
解决方案
C++98标准的相关文本§5.2.2/7:
在参数表达式上执行左值到右值(4.1)、数组到指针(4.2)和函数到指针(4.3)的标准转换。在这些转换之后,如果参数没有算术、枚举、指针、指向成员的指针或类类型,则程序的格式不正确。如果参数具有非POD类类型(第9条),则行为未定义。
因此正式行为未定义。
但是,给定的编译器可以提供任意数量的语言扩展,而Visual C++确实提供了。关于将参数传递给...
:,MSDN Library记录了Visual C++的行为
- 如果实际参数的类型为Float,则在函数调用之前将其提升为Double类型。
- 任何有符号或无符号的字符、短、枚举类型或位字段都使用整数提升转换为有符号或无符号整型。
- 类类型的任何参数都通过值作为数据结构传递;副本是通过二进制复制创建的,而不是通过调用类的复制构造函数(如果存在)来创建。
这篇文章没有提到有关Visual C++应用用户定义的转换的任何内容。
MSCString
被巧妙地布局,因此它的POD表示恰好是指向其以空结尾的字符串的指针。(sizeof(CStringA) == sizeof(char*)
)当它在任何printf样式函数中使用时,该函数Get只是传递了字符指针。
由于上面的最后一点和CString
的布局,所以这是可行的。
相关文章