У меня имелось несколько int и float переменных, которые я записывал в символьный массив примерно так:
char Msg[256];
sprintf(Msg, "%d %d %f %f",
m_nTemp1, m_nTemp2, m_fTemp3, m_fTemp4);
Теперь мне надо эти и еще несколько переменных и массивов запихнуть в структуру.
ВОПРОС: как полученную структуру перевести в символьный массив char Msg[256]?
Здравствуйте, Вов и К, Вы писали:
ВИК>У меня имелось несколько int и float переменных, которые я записывал в символьный массив примерно так: ВИК> char Msg[256]; ВИК> sprintf(Msg, "%d %d %f %f", ВИК> m_nTemp1, m_nTemp2, m_fTemp3, m_fTemp4); ВИК>Теперь мне надо эти и еще несколько переменных и массивов запихнуть в структуру. ВИК>ВОПРОС: как полученную структуру перевести в символьный массив char Msg[256]?
Ответы:
1. Если необходимо выводить в строку значения используй такой же финт и для каждого из полей структуры. Тут других вариантов нету.
2. Если необходимо просто хранить структуру в строке (как области памяти), то просто заполняешь структуру, а потом: struct _Struct {int a;} _s;
_s.a = 10;
...
char* _str = &_s;
Опиши более подробно твою ситуацию — может помогу.
Здравствуйте, Вов и К, Вы писали:
ВИК>У меня имелось несколько int и float переменных, которые я записывал в символьный массив примерно так: ВИК> char Msg[256]; ВИК> sprintf(Msg, "%d %d %f %f", ВИК> m_nTemp1, m_nTemp2, m_fTemp3, m_fTemp4); ВИК>Теперь мне надо эти и еще несколько переменных и массивов запихнуть в структуру. ВИК>ВОПРОС: как полученную структуру перевести в символьный массив char Msg[256]?
В С++ для этих целей пользуются
(1) перегрузкой функций...
Например, для вывода в любой текстовый поток общепринято завести семейство операторов <<
тогда вывод структуры можно рекурсивно определить через вывод её полей
struct Foo
{
int x;
double y;
Bar z; // ещё какая-то структура
Buz t[10]; // и даже массив
};
inline std::ostream& operator<< (std::ostream& ostr, const Foo& foo)
{
ostr << "{ ";
ostr << x << " " << y << " "<< z << " "; // предполагаем, что такой оператор есть и для Bar
std::copy(t,t+10, std::ostream_iterator<Buz>(ostr, " ")); // маленькая хитрость - копирование массива в поток
// превращается внутри в ostr << t[0] << " " << t[1] << " " ...
ostr << "}";
return ostr;
}
(2) и полиморфными объектами
Если ты решился делать всё через потоки (благо, для них уже много чего имеется в STL), обрати внимание: всё семейство operator<< принимает слева ostream. Это базовый класс, наследники которого — файловые и консольные потоки, но не только. Один из них — ostringstream — всё выводимое коллекционирует в строку.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Вов и К, Вы писали:
К>(2) и полиморфными объектами К>Если ты решился делать всё через потоки (благо, для них уже много чего имеется в STL), обрати внимание: всё семейство operator<< принимает слева ostream. Это базовый класс, наследники которого — файловые и консольные потоки, но не только. Один из них — ostringstream — всё выводимое коллекционирует в строку. К>
std::ostringstream oss;
oss << foo;
std::string s = oss.str();
d:\work\Debug\test\test.cpp(70) : error C2079: 'oss' uses undefined class 'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
d:\work\Debug\test\test.cpp(70) : see reference to class template instantiation 'std::basic_ostringstream<_Elem,_Traits,_Alloc>' being compiled
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
d:\work\Debug\test\test.cpp(70) : see reference to class template instantiation 'std::basic_ostringstream<_Elem,_Traits,_Alloc>' being compiled
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Alloc=std::allocator<char>
]
d:\work\Debug\test\test.cpp(71) : error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'int' (or there is no acceptable conversion)
d:\work\Debug\test\test.cpp(72) : error C2228: left of '.str' must have class/struct/union type
type is 'int'
Что я не так делаю?
Заранее прошу извинения за глупые вопросы. Я только начинаю вникать в С++ и STL
Здравствуйте, ZeusSon, Вы писали:
ZS>Здравствуйте, Вов и К, Вы писали:
ВИК>>У меня имелось несколько int и float переменных, которые я записывал в символьный массив примерно так: ВИК>> char Msg[256]; ВИК>> sprintf(Msg, "%d %d %f %f", ВИК>> m_nTemp1, m_nTemp2, m_fTemp3, m_fTemp4); ВИК>>Теперь мне надо эти и еще несколько переменных и массивов запихнуть в структуру. ВИК>>ВОПРОС: как полученную структуру перевести в символьный массив char Msg[256]?
ZS>Ответы: ZS>1. Если необходимо выводить в строку значения используй такой же финт и для каждого из полей структуры. Тут других вариантов нету. ZS>2. Если необходимо просто хранить структуру в строке (как области памяти), то просто заполняешь структуру, а потом: struct _Struct {int a;} _s; ZS>_s.a = 10; ZS>... ZS>char* _str = &_s;
ZS>Опиши более подробно твою ситуацию — может помогу.
ОК. Попытаюсь объяснить поподробнее.
Два хоста соединены по Ethernet. С одного на другой надо передать набор данных.
Было реализовано примерно так.
Это накладывает определенные ограничения на порядок чтения. Т.е. sscanf(...) на приемнике надо выполнять в том же порядке. А параметров в функции у меня сейчас скопилось довольно много. Вот и хотелось бы сделать структуру примерно такую:
struct foo
{
int Temp1;
int Temp2;
double Temp3;
double Temp4;
char Temp5[10];
...
}
Потом присвоить элементам какие-то значения и вывести всю область памяти, занимаемую структурой в строковый поток.
Далее на приемном хосте произвести обратную операцию извлечения из строкового потока в структуру и работать дальше с принятыми данными.
(Проблема передачи по сети не рассматривается. Главное требование буфер для приема-передачи должен быть char)
Как я понимаю, у меня проблема именно в конвертации структуры в строковый поток и последующей правильной обратной операцией на приемном хосте.
Здравствуйте, Вов и К, Вы писали:
К>>Так ты определил ostream& operator<<(ostream& ost, const Foo& foo) или нет?
ВИК>А надо? Я подумал, что это только для варианта 1. ВИК>Что, все-таки надо расписывать вывод каждого поля структуры, как в варианте 1?
Конечно. "перегрузка функций и полиморфизм".
Это было как бы объяснение, что стоит за оператором <<.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Вов и К, Вы писали:
К>>>Так ты определил ostream& operator<<(ostream& ost, const Foo& foo) или нет?
ВИК>>А надо? Я подумал, что это только для варианта 1. ВИК>>Что, все-таки надо расписывать вывод каждого поля структуры, как в варианте 1?
К>Конечно. "перегрузка функций и полиморфизм". К>Это было как бы объяснение, что стоит за оператором <<.
Тогда чем это все лучше, чем если я напишу что-то типа:
Опять же надо перечислять все переменные в определенном порядке.
Кстати не понятно, как потом их считывать.
А я бы хотел, если это возможно в принципе, сконвертить область памяти занимаемую ВСЕЙ структурой в char* или CString например, прицепить затем к этому делу хидер, а на обратном конце проделать обратную операцию — отделить хидер и переконвертить принятый кусок в структутру.
Если это в принципе невозможно, тогда прижется использовать последовательное занесение параметров. тогда мне структура вообще не нужна.
Здравствуйте, Вов и К, Вы писали:
ВИК>Тогда чем это все лучше, чем если я напишу что-то типа:
Лучше лишь тем, что тебе не придётся копипастить этот код, если вдруг такое потребуется ещё где-то.
ВИК>Опять же надо перечислять все переменные в определенном порядке. ВИК>Кстати не понятно, как потом их считывать.
ВИК>А я бы хотел, если это возможно в принципе, сконвертить область памяти занимаемую ВСЕЙ структурой в char* или CString например, прицепить затем к этому делу хидер, а на обратном конце проделать обратную операцию — отделить хидер и переконвертить принятый кусок в структутру. ВИК>Если это в принципе невозможно, тогда прижется использовать последовательное занесение параметров. тогда мне структура вообще не нужна.
А вот эта штука называется "сериализация". И она не сводится к простому распечатыванию в строку и последующему вычитыванию.
Вообще, вывод в текстовое представление для чтения человеком, и в последовательное (необязательно текстовое) представление для последующего восстановления (десериализации) — совершенно разные задачи.
Кодт wrote:
> Вообще, вывод в текстовое представление для чтения человеком, и в > последовательное (необязательно текстовое) представление для > последующего восстановления (десериализации) — совершенно разные задачи. > Поищи по форуму (да и по гуглу тоже).
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Вов и К, Вы писали:
ВИК>>У меня имелось несколько int и float переменных, которые я записывал в символьный массив примерно так: ВИК>> char Msg[256]; ВИК>> sprintf(Msg, "%d %d %f %f", ВИК>> m_nTemp1, m_nTemp2, m_fTemp3, m_fTemp4); ВИК>>Теперь мне надо эти и еще несколько переменных и массивов запихнуть в структуру. ВИК>>ВОПРОС: как полученную структуру перевести в символьный массив char Msg[256]?
К>В С++ для этих целей пользуются
К>(1) перегрузкой функций...
К>Например, для вывода в любой текстовый поток общепринято завести семейство операторов << К>
К>тогда вывод структуры можно рекурсивно определить через вывод её полей К>
К>struct Foo
К>{
К> int x;
К> double y;
К> Bar z; // ещё какая-то структура
К> Buz t[10]; // и даже массив
К>};
К>inline std::ostream& operator<< (std::ostream& ostr, const Foo& foo)
К>{
К> ostr << "{ ";
К> ostr << x << " " << y << " "<< z << " "; // предполагаем, что такой оператор есть и для Bar
К> std::copy(t,t+10, std::ostream_iterator<Buz>(ostr, " ")); // маленькая хитрость - копирование массива в поток
К> // превращается внутри в ostr << t[0] << " " << t[1] << " " ...
К> ostr << "}";
К> return ostr;
К>}
К>
К>(2) и полиморфными объектами К>Если ты решился делать всё через потоки (благо, для них уже много чего имеется в STL), обрати внимание: всё семейство operator<< принимает слева ostream. Это базовый класс, наследники которого — файловые и консольные потоки, но не только. Один из них — ostringstream — всё выводимое коллекционирует в строку. К>
прошу прощения за навязчивость. С вышеизложенным я разобрался. А как сделать обратную операцию из строкового потока в структуру. Куда считывать пробелв между элементами?
(оверквотинг покусан)
ВИК>прошу прощения за навязчивость. С вышеизложенным я разобрался. А как сделать обратную операцию из строкового потока в структуру. Куда считывать пробелв между элементами?
А никуда. Определяешь istream& operator>>(istream& ist, YourType& var)
и все числа будут считаны через пробелы, а вот со строками уже сложности.
Дело в том, что ost<<str пишет строку str как есть, а ist>>str читает до разделителя (пробела или перевода каретки).
Если str содержала разделители, получаем неприятность.
Чтобы избежать этого, можно, например, закодировать строку. Примерно так:
string percent_encode(string s)
{
// заменить все спецсимволы (0x01-0x20) на читаемые последовательности
string dst;
for(int i=0; i<s.size(); ++i)
{
char c = s[i];
char buf[4];
if(c=='%' || isspace(c) || iscntrl(c)) { sprintf(buf, "%%%02X", (unsigned char)c); dst += buf; }
else { dst += c; }
}
return dst;
}
string percent_decode(string s)
{
// восстановить спецсимволы из %XX
string dst;
for(int i=0; i<s.size(); )
{
char c = s[i];
if(isspace(c) || iscntrl(c)) { ++i; } // игнорируем пробельные символы, их просто не должно бытьelse if(c != '%') { dst += c; ++i; }
else { char buf[] = { '0', 'x', s[i+1], s[i+2], 0 }; c = atoi(buf); dst += c; i += 3; }
}
return dst;
}
(конечно, алгоритм неоптимальный. перепиши его на свой вкус).