when I use ostringstream, the only value that i get is : COM1
I have an application, which sends data.
I am using the code as :
std::ostringstream values;
values << someStruct.someValues;
...
...
std::string data
data << values.str();
But when I run this, all I get is an output saying COM1. My application is a DLL file.
But when I do this method below, I get the correct values
char *data;
char values[20];
sprintf(values, "%d",someStruct.someValue);
strcat(data,values);
But I don't want to use the above method as I have many variables that I need to fetch from the program. So someone please help.
std::string data;
data << values.str();
std::string is not a stream. It can't take operator<<. I'm surprised this code even compiles, but it almost certainly doesn't do something useful. What you want is this:
std::string data = values.str();
Related
I'm trying to use cereal to deserialize a JSON message. The (current) message structure is as follows:
"A":"B",
"C":{"D":"E","F":"G","H":"I"},
"J":"K",
"L":"M",
"N":{"O":{"P":"Q"}}}
The most important piece of data is "Q."
I can read all the normal strings easily. I was able to read the top-level items easily. I eventually was able to read "D"-"I" by treating "C" as an array (despite the lack of "["and "]"). However, I am unable to archive "N" as a string, array, vector, or object. It simply fails the respective IsString(), IsObject(), etc check on the iarchive(C); line. I see a GetType(), but I don't know to call that on "N" because anything I try to do with "N" fails.
I then was able to break the string down to just
{"O":{"P":"Q"}}
great, so just "C", but even simpler. Unfortunately, I had the same issue as before.
I then broke it down to just {"P":"Q"} and was able to finally get the value of Q via iarchive(value)
std::string msgtype,protocol_version, command, radio1_frequency,value;
std::string unit_id[3];
std::stringstream ss(msg->get_payload());
{//at this point, ^ss has the same format as outlined above, from "A" to "Q."
cereal::JSONInputArchive iarchive(ss);
iarchive(CEREAL_NVP(msgtype), CEREAL_NVP(protocol_version), CEREAL_NVP(command),CEREAL_NVP(unit_id));<-----------------------
}
rapidjson::Document doc;
doc.Parse((msg->get_payload()).c_str());
const rapidjson::Value& vars = doc["variables"];//<--this string is N
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
vars.Accept(writer);
std::stringstream sst(sb.GetString());
std::cout << sst.str() << "\n"; //here, sst has {"O":{"P":"Q"}}
doc.Parse(sb.GetString());
const rapidjson::Value& val = doc["radio1_frequency"];//<--this string is O
sb.Clear();
rapidjson::Writer<rapidjson::StringBuffer> writerTwo(sb);
val.Accept(writerTwo);
std::cout << sb.GetString() << "\n";//ss3 will now have {"P":"Q"}
std::stringstream ss3(sb.GetString());
{
cereal::JSONInputArchive iarchive(ss3);
iarchive((value));
std::cout << value << '\n';//Q
}
if I add ,CEREAL_NVP(variables) to the line with the arrow, I get the following output:
terminate called after throwing an instance of 'cereal::RapidJSONException'
what(): rapidjson internal assertion failure: IsString()
Child terminated with signal = 0x6 (SIGABRT)
To be clear, I get the result that I want, Q. I just feel like there must be a better way. I feel like the root of the problem is that I am unable to identify what type N is. Since I don't know the type, I don't know how to properly archive it in cereal. What can I do better inside the realm of C++11 and cereal, which uses rapidjson?
I wonder if it is because "O" has a number in the middle of the string and that is throwing it off. I should hope not because that's a valid string I believe
edit: I forgot to mention that "O" can change. so I won't be able to hardcode that in doc["N"]["O"]["P"]
I am making a rogue-like ASCII game and made a struct called "Armor" and I want to use the name variable in the struct to have the path to whatever the name is.
struct Armor {
bool equipped;
std::string name;
int getBuff(int buff) {
std::fstream item;
std::string line;
std::string response;
std::string value;
item.open("../Data/Items/" + name + ".item", std::fstream::in);
if (item.fail())
errorQuit("ERROR: There was a problem loading armor type .ITEM file."); // Error and quit function
while (!item.eof()) {
getline(item, line);
response = split(line, '=', 0); // Splits string
if (response == "buff" + std::to_string(buff)) {
value = split(line, '=', 1);
break;
}
}
item.close();
return std::stoi(value);
}
};
Then I called it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1);
But this throws an Unhandled exception error.
I changed it so that getBuff takes 2 parameters, int buff and std::string itemName. and replaced name in the path with itemName;
Then I tried calling it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1, sword.name);
But this throws the same error.
I'm confused as to why I can't use the name variable as it has already be defined. Is there any other way I can use the name variable like that?
I see you've just edited your comment to say you've figured your problem out, but I just want to add something else that may be helpful:
Without seeing how errorQuit() is defined, there's a potential problem in your getBuff() function. If the expression if (item.fail()) evaluates to true, the function may continue on trying to process the data (unless errorQuit() somehow breaks out of the program or something, which probably isn't the best approach).
Basically, testing for fail() may or may not provide the behavior you require in all scenarios, depending on what bits are set in the stream state. Implementations vary, but... if the file fails to open, failbit and/or badbit will be set, but not eofbit. getline() will see the error state and so it will not try to read from the stream when you call it. But that also means the eofbit will never be set!
There's lots of different "techniques" to file reading. Some people prefer an RAII approach. Others like looping on getline(). Or you could even just use good() to check the error state if you don't care what happened and simply want to know if everything is fine or not.
In any case, you might be interested in the info on this page: std::ios_base::iostate.
Thanks for all your help but I figured it out on my own.
I just made a stupid error that I overlooked like an idiot.
It is searching for buff + int (e.x. buff1) in the file but there are multiple lines that contain that word so I guessed that messed it up. I just made an adjustment to the if statement and it is working as expected.
Sorry to bother you!
your getBuf() function fails on some io-operation and throws an exception.You dont handle exceptions and thus the application quits with the appropriate message. Try surrounding the call to getBuf with try/catch (add the includes to iostream and stdexcept)
try {
int buff = sword.getBuff(1);
}
catch (const std::exception &e) {
std::cout << e.what() << std::endl;
}
i am working on a network project of mine in order to learn more about networking and right now i have designed a simple protocol/structure that i fill and send to the server, the problem is that all vectors and probably arrays aswell are invalid on the server side.
im gonna try to explain it with code, its alot easier that way.
My protocol:
typedef struct NETWORK_PROTOCOL {
int packet_size;
int number_of_data_files;
std::vector<std::string> data_files;
}
so its a pretty simple protocol, and what i did is that i fill it with data and its completely valid on the client side, however as soon as i send it to the server and try to convert it back it the vector is invalid but the integers are still valid.
this is how i create and send the data from the client:
NETWORK_PROTOCOL Protocol;
//Fills protocol with data
int sendt = send(ClientSocket, (const char*)&Protocol, Protocol.packet_size, 0);
and when it hits the server i still get the full size of the data, but as i said earlier it does not convert back properly :/
Code on the server side that tries to cast it back:
NETWORK_PROTOCOL* Protocol;
iResult = recv(ClientSocket, buffer, BUFFLEN, 0);
//then i have some validation code to check if the whole packet arrived since its TCP
Protocol = reinterpret_cast<NETWORK_PROTOCOL*>(buffer);
//And now the vector is invalid :/
im not really sure how to fix this problem, i thought it would be easy to convert it back since it is the exact same data on both sides. Any help to fix this issue is greatly appreciated.
std::vector can't be transferred this way: internally it uses pointers, so you send only a pointer, without any actual information, and that pointer is not valid on the receiving side.
In order to send the contents of vector, you need to somehow serialize it (convert it to the representation in which it can be easily transferred). For example, you can use is Boost.Serialization
#include <sstream>
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
struct NETWORK_PROTOCOL
{
private:
friend class boost::serialization::access;
// When the class Archive corresponds to an output archive, the
// & operator is defined similar to <<. Likewise, when the class Archive
// is a type of input archive the & operator is defined similar to >>.
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & packet_size;
ar & number_of_data_files; // you don't actually need it
ar & data_files;
}
public:
int packet_size;
int number_of_data_files;
std::vector<std::string> data_files;
};
Now you can serialize it like this:
std::ostringstream ofs;
boost::archive::text_oarchive oa(ofs);
oa << protocol; // protocol is your instance of NETWORK_PROTOCOL, which you want to send
// and then you'll be able to get a buffer from ofs using ofs.str()
Deserialize it like this:
NETWORK_PROTOCOL protocol;
std::istringstream ifs(buf);
boost::archive::text_iarchive ia(ifs);
ia >> protocol;
For practical usages you may want to use binary archives instead. If you decide to go with boost.serialization, I recommend starting looking here.
You may also like Google Protocol Buffers: https://developers.google.com/protocol-buffers/docs/cpptutorial
This comment is longer than allowed. So I put it as an answer; although I think it answers partially.
To send all the data in one shipment wasted space and bandwidth, because you'd have to take a maximum for the number of names and their sizes. So I suggest you divide your transmission in phases.
In the first phase you send the number of filenames that you are transmitting. In this way you prepare the server for receiving n file names. Then in the second phase you make a loop divided in two transmissions. The first transmission you send the file name size, then you prepare a buffer for receiving the filename.
For these modes you only use basic types (size_t and char *).
On the server side you can build your vector<string>, if you want to give that illusion
I hope it helps you
I'm implementing a data buffer which receives audio data packages with procedure call (no network protocols just two applications running on same machine) from one application and puts it in a Struct and writes to a mapped file.
So the writer application may call my app's procedure, which would be smth like void writeData (DataItem data, Timestamp ts) for about 15 times a second with each data item size 2MB.
My app shall store the data into a struct like
Struct DataItem
{
long id;
... Data;
Time insertTime;
}
and write it to a file for future reading purposes.
So since its hard to save the struct to the file as it is, I think(?) I need to write it as binary. So I'm not sure that I need to use any kind of serialization like boost serialization or not?
And I don't know how to align this data for memory map files, and how to re-construct the data for reading purpose from the file as well.
I search internet but I couldn't find much code example. And sample code would be higly appriciated.
By the way I'm using Windows 7 x64 embedded and Visual Studio 2008.
Thanks...
A common C++ way to serialize would be:
struct myStruct
{
int IntData;
float FloatData;
std::string StringData;
};
std::ostream& operator<<(std::ostream &os, const myStruct &myThing)
{
os
<< myThing.IntData << " "
<< myThing.FloatData << " "
<< myThing.StringData << " "
;
return os;
}
std::istream& operator>>(std::istream &is, myStruct &myThing)
{
is
>> myThing.IntData
>> myThing.FloatData
>> myThing.StringData;
return is;
}
void WriteThing()
{
myStruct myThing;
myThing.IntData = 42;
myThing.FloatData = 0.123;
myThing.StringData = "My_String_Test";
std::ofstream outFile;
outFile.open("myFile.txt");
outFile << myThing;
}
void ReadThing()
{
myStruct myThing;
std::ifstream inFile;
inFile.open("myFile.txt");
inFile >> myThing;
}
Please Note:
std::string defines operators << and >>. Those will be called in the
code above.
streams will treat white space characters as delimiters. Storing Strings with blanks would require additional handling
If you plan to keep your data through updates of your
software, you must implement some sort of file versioning
refer to the docs of fstream to find out how to move the file pointer
using seek etc. on a single large file.
Use boost::serialization with text archive.
Is the most "standard" way of solving platform independence.
Optional, you can set a gzip compression on top of it.
Are you sure you are asking about C++ and not C#? Your code example looks like C#
In C++ If your struct format is not going to change, then you can just write the array out to disk.
here is an example as you requested, but this is really C 101 stuff
FILE* output=fopen ("myfile", "wb");
fwrite (array, sizeof (mystruct), number_of_elements_in_array, output);
fclose (output);
I try to write and read object of class into and from binary file in C++. I want to not write the data member individually but write the whole object at one time. For a simple example:
class MyClass {
public:
int i;
MyClass(int n) : i(n) {}
MyClass() {}
void read(ifstream *in) { in->read((char *) this, sizeof(MyClass)); }
void write(ofstream *out){ out->write((char *) this, sizeof(MyClass));}
};
int main(int argc, char * argv[]) {
ofstream out("/tmp/output");
ifstream in("/tmp/output");
MyClass mm(3);
cout<< mm.i << endl;
mm.write(&out);
MyClass mm2(2);
cout<< mm2.i << endl;
mm2.read(&in);
cout<< mm2.i << endl;
return 0;
}
However the running output show that the value of mm.i supposedly written to the binary file is not read and assigned to mm2.i correctly
$ ./main
3
2
2
So what's wrong with it?
What shall I be aware of when generally writing or reading an object of a class into or from a binary file?
The data is being buffered so it hasn't actually reached the file when you go to read it. Since you using two different objects to reference the in/out file, the OS has not clue how they are related.
You need to either flush the file:
mm.write(&out);
out.flush()
or close the file (which does an implicit flush):
mm.write(&out);
out.close()
You can also close the file by having the object go out of scope:
int main()
{
myc mm(3);
{
ofstream out("/tmp/output");
mm.write(&out);
}
...
}
Dumping raw data is a terrible idea, from multiple angles. This will break even worse once you add pointer data.
One suggestion would be to use Boost.Serialization which allows for far more robust data dumping.
Your main problem is the file does not contain the contents yet due to fstream buffering. Close or flush the file.
I'll echo "you shouldn't be doing this". If you print out sizeof(myc) in the code above it's probably 4, as you'd expect... BUT try changing read and write to be virtual. When I did so, it prints out the size as 16. Those 12 bytes are internal guts with sensitive values—and saving them out and then reading them back in would be like expecting a pointer value to be still good if you wrote it and loaded it again.
If you want to circumvent serialization and map C++ object memory directly to disk, there are ways to hack that. But rules are involved and it's not for the faint of heart. See POST++ (Persistent Object Storage for C++) as an example.
I'll add that you did not check the fail() or eof() status. If you had you'd have known you were misusing the fstream API. Try it again with:
void read(ifstream *in) {
in->read((char *) this, sizeof(myc));
if (in->fail())
cout << "read failed" << endl;
}
void write(ofstream *out){
out->write((char *) this, sizeof(myc));
if (out->fail())
cout << "write failed" << endl;
}
...and see what happens.
My C++ is pretty rust and highly under-tested, but you may want to take a look at Serialization and Unserialization. FAQ
I've done something similar using output.write((char*)&obj, sizeof(obj)), obj being an instance of your class. You may want to loop this if you want to write the data inside the object instead, which would generally be the case as you need members to be readable, right ?
Same thing for reading with read function. But if you have dynamic allocation to do then with this data, you need to handle it.