我正在编写一个C++程序,该程序需要对字符串中的某些值进行编码(它必须是字符串)。我决定使用 sprintf 将数据(一个无符号的 int 和两个双精度)保存在 char 数组中。问题是我在理解这个函数的行为时遇到了问题。这是我正在使用的代码
char vel[1];
unsigned int n = 30;
std::sprintf(vel, "%u", n);
std::cout<< "packet sending: " << vel << std::endl;
std::cout<< "packet dim: " << sizeof(vel)<< std::endl;
这是一个初步测试。由于无符号 int 是 4 个字节,而我只分配了一个 1 个字符(字节)的数组,我预计会出现分段错误 但是,令人惊讶的是(当然对我来说)得到了输出
packet sending: 30
packet dim: 4
其实我不明白为什么。此外,目标是存储三个值并使用scanf检索它们。如果可能的话,这是我想做的
char vel[1];
unsigned int n = 30;
std::sprintf(vel, "%u%f%f", n, 5.0,6.0);
std::cout<< "packet sending: " << vel << std::endl;
std::cout<< "packet dim: " << sizeof(vel)<< std::endl;
并在另一个函数中发送字符串
std::string s = vel.str();
我愿意
unsigned int i;
float g,h;
std::sscanf(s.c_str(), "%u%f%f",&i,&g,&h);
当然什么都没用,你能帮帮我吗?我阅读了所用函数的文档,但我不明白为什么这不起作用。谢谢!安德里亚
编辑:如果我使用以下代码生成一个字符串,我会运行一些测试:
char vel[13];
unsigned int n = 30;
std::sprintf(vel, "%u%f", n, 5.0);
std::stringstream packet;
packet << vel;
std_msgs::String outMsg;
outMsg.data = packet.str();
我尝试以这种方式检索信息:
packet = msg->data.c_str();
unsigned int i;
float f;
std::sscanf(packet, "%u%f", &i, &f);
std::cout << "received packet: "<< i << "tdata: "<< f << std::endl;
生成的打印是
received packet: 305 data: 0
它应该是
received packet: 30 data: 5
不应该吗?
再次感谢!
第一个代码输出的原因是:
packet sending: 30
packet dim: 4
这是因为sprintf
成功创建了一个字符串,即使vel
它只是 1 字节的字符数组。您的代码在 sprintf
内部的vel
上产生缓冲区溢出。并且可能可变n
被此溢出修改(在您不知道的情况下)。如果你打印n
的值,我想它不再30
了。
我猜这是您想在第一个代码上完成的:
char vel[42]; //42 = 11 + 1 + 14 + 1 + 14 + 1
unsigned int n = 30;
std::sprintf(vel, "%u %.5f %.5f", n, 5.0,6.0);
std::cout<< "packet sending: " << vel << std::endl;
std::cout<< "packet dim: " << strlen(vel)<< std::endl;
//Changes:
// - add spaces in your format string
// change "%u%f%f" to "%u %f %f" so sscanf() will know
// when to stop parsing a specific data.
// - replace sizeof(vel) with strlen(vel) because
// your sending a string that changes size.
// sizeof() is for getting the size of DATA TYPES only.
在接收器代码中,尝试更改 sscanf() 中的格式字符串:
std::sscanf(packet, "%u %f", &i, &f); //add space in the middle.
如果要使用sprintf
则必须提供足够大的缓冲区来存储所有字符。程序中给出的数组很小,因此函数会覆盖以下内存块,在末尾附加NULL
,然后将其正确打印到 stdout。调用sprintf
变量后n
可能不等于 30。此功能的更安全版本是 snprintf
。http://www.cplusplus.com/reference/cstdio/snprintf/http://www.cplusplus.com/reference/cstdio/sprintf/