【问题标题】:Printing std::string via printf() in Visual Studio在 Visual Studio 中通过 printf() 打印 std::string
【发布时间】:2012-05-18 16:27:12
【问题描述】:
#include <string>
#include <cstdio>
int main() {
  std::string s = "12345678";
  std::printf("[%s]\n", s);
}

这里是缺少“.c_str()”的明显错字。但是即使使用 /Wall VS2011 也不会发出任何警告,并且程序可以正常工作。如果要在 gcc 中编译此代码,它会显示“警告:无法通过 '...' 传递非 POD 类型的对象 'struct std::string';调用将在运行时中止”并且程序因“非法指令”而崩溃.

他们真的在 VS STL 中实现了一个技巧,让有这种错字的程序能够正常工作,只是因为这种错字很常见吗?

更新:问题是为什么它可以在 VS 中工作?

【问题讨论】:

  • 我不知道std::string,但他们的预标准CString 被设计成可以通过这种方式传递。如果编译器没有故意插入会导致崩溃的代码,我认为它实际上可以与 g++ 实现一起使用。
  • 这里有问题吗?它是在问这个案例在 Visual Studio 中做了什么或没做什么,还是他们在 gcc 中做了什么?
  • Kevin:问题是为什么它可以在 VS 中工作?
  • stackoverflow.com/questions/6820330/… - 你尝试过发布模式吗?
  • 好吧,给你。花园品种未定义的行为。

标签: c++ visual-c++ visual-studio-2012 std


【解决方案1】:

原因似乎是在 Visual Studio 的 std::string 实现中,第一个成员是 char*。通过值传递string 将此指针(以及其他数据成员)复制到堆栈上,%s 导致printf() 读取char* 并正确解释它,因为string 是必需的为空终止。

当然,这依赖于未定义的行为,您不应该这样做。

【讨论】:

  • +1 就是这样。但是,如果编译时类型检查需要 char*,它应该会失败,不是吗?
  • @NeelBasu 编译器应该如何知道一个函数打算做什么?
  • 因为它会尝试将其转换为char* for %s
  • @NeelBasu 不,它不会尝试将其投射到任何东西上。没有对可变参数函数进行类型检查,实际的 printf 函数只是盲目地将字节解释为你告诉它你给它的类型。它无法知道您实际发送的内容。
  • @NeelBasu:printf() 等可变参数函数(一般来说)没有经过类型检查。编译器尝试为潜在的格式字符串错误提供诊断,但这不是标准强制要求的。使用 va_arg() 读取错误类型的可变参数只会调用未定义的行为。
【解决方案2】:

之所以有效,是因为未定义行为的一种可能结果是程序按照您的意愿行事。你不需要再看这个了。未定义的行为是您简单地避免而不是试图理解它在一个特定编译器中的表现。

【讨论】:

  • 根据我的测试,它实际上并没有“工作”——也就是说,如果“工作”是指“它在控制台上打印“12345678”。对我来说,它打印垃圾,正如我所期望的那样。
  • @John 根据提问者的说法,32 位和 64 位目标的行为不同。但由于这是 UB,任何事情都可能发生。
猜你喜欢
  • 2013-12-07
  • 2019-11-08
  • 2015-10-20
  • 2023-03-11
  • 2019-05-14
  • 2018-05-13
  • 2019-11-09
相关资源
最近更新 更多