Я пишу программу 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;
Это предварительный тест. Поскольку unsigned int имеет 4 байта, и я выделяю массив только из 1 char (байт), я ожидаю ошибку сегментации. Однако я удивительно (для меня, конечно), получая вывод
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);
Конечно, ничего не работает, не могли бы вы мне помочь? Я прочитал документацию по используемой функции, но я не мог понять, почему это не работает. Спасибо! Andrea
EDIT: Я запускаю некоторые тесты, если я создаю строку со следующим кодом:
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
не так ли?
Еще раз спасибо!
Причина, по которой вывод вашего 1-го кода:
packet sending: 30
packet dim: 4
это потому, что sprintf
успешно создал строку, хотя vel
- только 1 байт. Ваш код создает переполнение буфера на vel
внутри sprintf
. И, вероятно, переменная 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/
vel
1 байты? Вам нужно как минимум 11 байтов для хранения 4-байтового значения без знака в виде строки. Рассмотрим значение 4294967295 (максимальное значение). Это 10 символов + 1, необходимых для завершающего нулевого символа.