如何解决将 printf 与 C++ 迭代器一起使用
在这种情况下,当我将 std::printf 与迭代器一起使用时,我不清楚发生了什么:
#include <string>
#include <vector>
#include <list>
#include <cstdio>
int main() {
std::string str{"hello,world"};
std::printf("%s\n",str.begin()); // prints "hello,world"
std::vector<char> vec(str.begin(),str.end());
std::printf("%s\n",vec.begin()); // still same output
std::list<char> lst(str.begin(),lst.begin()); // weird ascii outputs ???
}
我还使用了 va_arg(ap,char*)
仍然有效,并且行为方式与上面的代码相同,我有几个问题。
它适用于连续的数组(使用 RAI 迭代器)吗?还是UB?为什么即使 va_arg
也会允许这样的事情,是否有一些隐式转换?
解决方法
TL;DR:这都是无效的 C++,因为 std::printf
没有类型安全的 API。 将非 POD 对象的引用作为 std::printf
参数传递始终无效:printf
具有 C API。
在所有情况下发生的都是未定义的行为:您不应该编写那样的代码。语言规范本身并没有告诉你期望什么。这样的代码是一个错误,将无法通过任何合理的代码审查。
对于 std::string
和 std::vector
迭代器,它们碰巧具有相同的大小、值、布局和参数传递约定在您的平台上与 {{ 1}} const char *
期望,和它们恰好分别包含字符串/向量开头的地址。 printf
和 std::string
对数据数组的布局相同,即元素是连续的,巧合的是 std::vector<char>
中的内存块在字符串末尾有一个零,所以这恰好工作。也许它只是因为您在调试模式下构建而有效:)
对于 std::vector
迭代器的情况,它可能碰巧包含指向列表数据块头部的指针,或者指向包裹在列表项中的 std::list
开头的指针,并且因此,您会得到无意义的输出,但不会导致无效的内存访问,因为等效指针指向某个已分配的内存区域,否则有效。当然,这是您平台上实现细节的结果。有些平台和构建选项会使代码崩溃。不,你甚至不能指望它会可靠地崩溃。这就是UB很糟糕的原因。
在你的平台上,std::string
可能是一个同样糟糕的错误,但碰巧“工作”,因为 std::printf("%s\n",*lst.begin());
产生对 *lst.begin()
的引用,而这样的引用通常是像指针一样布置和传递。当然,这仍然是 UB,所以不要做任何事情!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。