看简化代码 - 我很困惑......
#include <stdio.h>
#include <string>
#include <cstdlib> // includes the standard library and overarchs over stdlib.h
using namespace std;
void main()
{
char buffer[10];
string theString;
int i = 997799; //(simplified)
itoa(i,buffer,10);
theString = buffer;
printf("\n string is: %s of length %d \n", theString, theString.length());
printf("\n buffer is: %s of length %d \n", buffer, theString.length());
return;
}
我得到的输出是意外的:
string is: (null) of length 926366009
buffer is: 997799 of length 6
(1)为什么字符串打印为空?
(2)为什么theString.length()在第一个printf()中没有正确打印,而是在第二个?#/ p>
(3)如果我在visual studio中设置断点'buffer'显示为“997799”,而'theString'显示为{“997799”} - 这里有什么奇怪的事情?
谢谢大家! 编辑我非常感谢所提供答案的详细程度 - 它们都增加了清晰度并帮助我超越了我的问题 - 非常感谢你花时间帮忙:)
答案 0 :(得分:3)
程序具有未定义的行为,因为函数printf无法输出std :: string类型的对象。当使用格式符号%s时,该函数假定相应的参数是字符串文字的指针。因此该函数尝试输出std :: string类型的对象作为字符串文字。 要正确使用函数printf和std :: string类型的对象,您应该使用成员函数c_str()或data()(对于C ++ 2011)将它们转换为字符串。例如
printf("\n string is: %s of length %ul \n", theString.c_str(), theString.length());
答案 1 :(得分:3)
当您将%s
说明符与printf()
一起使用时,您承诺传递char const*
作为相应的参数。传递除char const*
之外的任何内容或衰减为char const*
的内容都是未定义的行为。当然,传递C ++对象会有不确定的行为。
将std::string
传递给printf()
的正确方法是使用%s
格式说明符并使用c_str()
成员,例如:
printf("string=%s\n", s.c_str());
您使用%d
作为std::string::size_type
的格式说明符。这将可能工作,但不能保证工作!虽然std::string::size_type
保证为std::size_t
,但此类型可能是unsigned int
,unsigned long
,unsigned long long
,甚至是一些非标准的内置整数类型!拼写std::size_t
格式说明符的正确方法是%zu
(当然不是%ul
,如同另一篇文章:它可能是%lu
,但是,还是错的:
printf("string.size()=%zu\n", s.size());
由于您使用的是C ++,因此最好让编译器找出要调用的格式:
std::cout << "\n string is: " << theString << " of length " << theString.length() << " \n";
std::cout << "\n buffer is: " << buffer << " of length " << theString.length() << " \n";
答案 2 :(得分:0)
我的编译器(os x上的clang)报告以下错误:
c++ foo.cc -o foo
foo.cc:6:1: error: 'main' must return 'int'
void main()
^~~~
int
foo.cc:11:5: error: use of undeclared identifier 'itoa'
itoa(i,buffer,10);
^
foo.cc:14:48: error: cannot pass non-POD object of type 'string' (aka
'basic_string<char, char_traits<char>, allocator<char> >') to variadic
function; expected type from format string was 'char *'
[-Wnon-pod-varargs]
printf("\n string is: %s of length %d \n", theString, theString.length());
~~ ^~~~~~~~~
foo.cc:14:48: note: did you mean to call the c_str() method?
printf("\n string is: %s of length %d \n", theString, theString.length());
^
.c_str()
foo.cc:14:59: warning: format specifies type 'int' but the argument has type
'size_type' (aka 'unsigned long') [-Wformat]
printf("\n string is: %s of length %d \n", theString, theString.length());
~~ ^~~~~~~~~~~~~~~~~~
%lu
foo.cc:15:56: warning: format specifies type 'int' but the argument has type
'size_type' (aka 'unsigned long') [-Wformat]
printf("\n buffer is: %s of length %d \n", buffer, theString.length());
~~ ^~~~~~~~~~~~~~~~~~
%lu
让我们解决它们:
void main() { ... }
应为int main() { ... }
。
itoa()
在C ++中不是标准的。但是有std::stoi()
,所以让我们使用它。如果我们写入字符数组而不是std::string
,我们也可以使用std::snprintf
。
如果我们要将printf()
与std::string
一起使用,我们需要使用std::string::c_str()
方法返回一个字符数组并进行打印。 printf本身不了解C ++对象。 (我们也可以使用cout,它确实理解c ++对象。)
这些更改会导致代码如下:
#include <cstdio>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
char buffer[10];
string theString;
int i = 997799; //(simplified)
snprintf(buffer, sizeof(buffer), "%d", i);
theString = buffer;
printf("string is: %s of length %lu\n", theString.c_str(), theString.length());
printf("buffer is: %s of length %lu\n", buffer, strlen(buffer));
}
此代码输出:
[4:46pm][wlynch@watermelon /tmp] ./foo
string is: 997799 of length 6
buffer is: 997799 of length 6
答案 3 :(得分:0)
正如另一个答案指出的那样,(null)
值的原因是因为(正式)printf
%s
期望输入const char*
,{{1}是不一个std::string
并导致未定义的行为...当您执行第一个const char*
时随机数的原因与您的编译器有关。
在带有g ++ 4.2.1的OpenBSD 5.1上,当我编译代码时,我收到了很多警告;一个特别是使用theString.length()
,我必须更改为itoa
,我还会在sprintf
%s
上收到关于printf
std::string
的以下警告:{ {1}}。
当我运行已编译的代码时,由于在warning: cannot pass objects of non-POD type 'struct std::string' through '...'; call will abort at runtime
'对象'上调用printf
,它会在第一个%s
中止和核心转储(这是'正确的'行为虽然技术上仍然是“未定义的行为”)
但是,当我在MS编译器上编译上面的代码(没有编辑)时,我实际得到以下输出:
std::string
仍然是“未定义”,但“预期”结果。
显然,MS编译器识别string is: 997799 of length 6
buffer is: 997799 of length 6
上的std::string
并将其“更改”为printf
调用或MS C / C ++库中的string.c_str()
接受printf
并为您调用std::string
。
因此要100%兼容'和C ++'兼容'考虑以下内容:
.c_str()
混合使用C ++和C调用/样式通常不是一个好习惯,但恕我直言我使用#include <iostream>
#include <sstream>
int main(int argc, char **argv)
{
std::stringstream theString;
int i = 997799; //(simplified)
theString << i;
std::cout << "string is: " << theString.str() << " of length " << theString.str().length() << std::endl;
// printf("string is: %s of length %d \n", theString.str().c_str(), theString.str().length());
return 0;
}
因为它的“方便”但通常将其取出或使用一些printf
进行调试构建使用仅
我希望能帮助回答“为什么#2”