C++ 将printf与C++;迭代器

C++ 将printf与C++;迭代器,c++,iterator,C++,Iterator,在这种情况下,当我将std::printf与迭代器一起使用时,我不清楚会发生什么: #包括 #包括 #包括 #包括 int main(){ string str{“你好,世界”}; std::printf(“%s\n”,str.begin());//打印“你好,世界” 向量向量(str.begin(),str.end()); std::printf(“%s\n”,vec.begin());//输出仍然相同 std::list lst(str.begin(),str.end()); std::pr

在这种情况下,当我将std::printf与迭代器一起使用时,我不清楚会发生什么:

#包括
#包括
#包括
#包括
int main(){
string str{“你好,世界”};
std::printf(“%s\n”,str.begin());//打印“你好,世界”
向量向量(str.begin(),str.end());
std::printf(“%s\n”,vec.begin());//输出仍然相同
std::list lst(str.begin(),str.end());
std::printf(“%s\n”,lst.begin());//奇怪的ascii输出???
}
我还使用了实用程序来模拟printf的行为,它看起来即使与
va_arg(ap,char*)
一起也能工作,并且行为与上面的代码相同,我有几个问题。
它是否适用于连续的数组(使用RAI迭代器)?或者是UB?为什么即使是
va_arg
也会允许这样的事情,有一些隐式转换吗?

TL;DR:这都是无效的C++,因为
std::printf
没有类型安全的API将引用作为
std::printf
参数传递给非POD对象总是无效的
printf
具有C API

所有情况下发生的都是未定义的行为:您不应该这样编写代码。语言规范本身并没有告诉您预期会发生什么。这样的代码是一个bug,任何合理的代码审查都会失败

对于
std::string
std::vector
迭代器,它们恰好与
printf
所期望的
const char*
在平台上具有相同的大小、值、布局和参数传递约定,并且它们恰好分别包含字符串/向量开头的地址。
std::string
std::vector
都以相同的方式布置数据数组,即元素是连续的,并且正好
std::vector
中的内存块在字符串的末尾有一个零,因此这恰好起作用。可能它只在调试模式下运行:)

对于
std::list
迭代器的情况,它可能恰好包含指向列表数据块标题的指针,或指向列表项中包装的
std::string
开头的指针,因此您会得到无意义的输出,但不会导致无效的内存访问,因为等效指针指向某个分配的内存区域,并且在其他方面是有效的。当然,这是平台上实现细节的结果。在某些平台和构建选项中,代码将崩溃。不,你甚至不能相信它会可靠地崩溃。这就是为什么UB很糟糕的原因


在您的平台上,
std::printf(“%s\n”,*lst.begin())
很可能是一个同样糟糕的bug,但却碰巧“起作用”,因为
*lst.begin()
生成了对
std::string
的引用,并且这种引用通常像指针一样被布置和传递。当然,这仍然是UB,所以不要做任何事情

TL;DR:这都是无效的C++,因为
std::printf
没有类型安全的API将引用作为
std::printf
参数传递给非POD对象总是无效的
printf
具有C API

所有情况下发生的都是未定义的行为:您不应该这样编写代码。语言规范本身并没有告诉您预期会发生什么。这样的代码是一个bug,任何合理的代码审查都会失败

对于
std::string
std::vector
迭代器,它们恰好与
printf
所期望的
const char*
在平台上具有相同的大小、值、布局和参数传递约定,并且它们恰好分别包含字符串/向量开头的地址。
std::string
std::vector
都以相同的方式布置数据数组,即元素是连续的,并且正好
std::vector
中的内存块在字符串的末尾有一个零,因此这恰好起作用。可能它只在调试模式下运行:)

对于
std::list
迭代器的情况,它可能恰好包含指向列表数据块标题的指针,或指向列表项中包装的
std::string
开头的指针,因此您会得到无意义的输出,但不会导致无效的内存访问,因为等效指针指向某个分配的内存区域,并且在其他方面是有效的。当然,这是平台上实现细节的结果。在某些平台和构建选项中,代码将崩溃。不,你甚至不能相信它会可靠地崩溃。这就是为什么UB很糟糕的原因


在您的平台上,
std::printf(“%s\n”,*lst.begin())
很可能是一个同样糟糕的bug,但却碰巧“起作用”,因为
*lst.begin()
生成了对
std::string
的引用,并且这种引用通常像指针一样被布置和传递。当然,这仍然是UB,所以不要做任何事情

乌布。。。你正在访问原始数据并用其他格式解释它,发生的事情是你使用的是C++类,C库函数对任何与C++相关的东西都没有线索。任何你可能看到或可能看不到的合理结果都纯粹是随机的运气<代码> Prtff<代码>不能保证与任何迭代器或C++类一起工作,即使今天工作,也可能在下次更新C++编译器时神秘地停止工作,或者如果下星期一它会停止工作,如果感觉像这样。@ SimAMT未定义的行为是未定义的,这包括“看起来像预期的工作一样”。但是您的假设可能是正确的,连续容器似乎最有可能在这种情况下工作。您得到的
vector
不是以null结尾的,因此即使
vec.begin()