Convert structor to string

Nov 17, 2011 at 9:53am
How to convert structor to string?
Nov 17, 2011 at 12:02pm
Write conversion code.

For more details, provide more question.
Nov 17, 2011 at 7:10pm
Here's a way to convert a struct to a string.

1
2
3
4
5
6
7
8
9
	#include <ctime>
	std::string myString;
	//Time computations
	struct tm LocalTime;
	__time32_t aclock;
	_time32( &aclock );   // Get time in seconds.
	_localtime32_s( &LocalTime, &aclock );   // Convert time to struct tm form.

	asctime_s(&myString,LocalTime);
Nov 18, 2011 at 8:49am
How about the structure on data not on time?
Nov 18, 2011 at 5:11pm
1
2
3
4
5
6
7
8
9
std::string structToString (someStructureType* theStruct)
{
  char* tempCstring = new char[sizeof(someStructureType)+1];
  memcpy(tempCstring, theStruct, sizeof(someStructureType));
  tempCstring[sizeof(someStructureType)+1] = '0';
  std::string returnVal(tempCstring, sizeof(someStructureType));
  delete tempCstring;
  return returnVal;
}



This code is horrific. It turns any structure into a string. There is no interpretation, just blind copy. If there is a zero value in the data somewhere, it'll might get truncated (and I've stuck one on the end of the C style string used as a halfway-house, just to be sure it's terminated, out of a nervous reflex); possibly the string constructor I've used ignores zero-termination of C style strings (as I specified a size). I'd have to look it up (or just experiment) to be sure.

Make no mistake; what this does is truly hideous and is asking for all sorts of trouble.
Last edited on Nov 18, 2011 at 5:12pm
Nov 18, 2011 at 7:17pm
@OP: Really ¿what do you want to do? ¿a serialization?

'\0' and delete []
Off topic: ¿Can that be done directly in the std::string?
Nov 19, 2011 at 12:59am
Off topic: ¿Can that be done directly in the std::string?


Right now, don't know. Banged it all out in sixty seconds before going to Friday pub. When I sober up, I'll either tidy it up, or wonder what I was thinking even answering :)

Nov 19, 2011 at 12:53pm
Copying the bytes of the structure into the buffer of a string does not look like conversion to me. If you want to deal with the bytes directly, you'd be better off just writingthe bytes directly to file, e.g. ofsteam::write(), so it's clear what's going on.

In addition to 0 bytes embedded in the struct "string", which Mochops mentioned, there would also be a big problem with pointer members.

As ne555 asked, what is the conversion required for? Is it for serialization? Or just for display purposes?

Whatever, you will need to code a structure function. Probably easiest with the help of ostringstream (if you like iostreams?)

Andy
Last edited on Nov 19, 2011 at 12:58pm
Nov 19, 2011 at 9:54pm
I just thought of another method:
1
2
3
4
5
std::string Struct2String(void* StructIn)
{
    std::string* StringOut = static_case<std::string*>(StructIn);
    return StringOut;
}


Would that work? An easier alternative might be a character array:

1
2
3
4
5
char Struct2String(void* StructIn)
{
    char* StringOut = static_case<std::string*>(StructIn);
    return StringOut;
}
Last edited on Nov 19, 2011 at 9:55pm
Nov 20, 2011 at 12:37am
8-0 Has this become a competition to come up with the scariest possible bit of code???

Telling the compiler that a random bit of memory is a std::string would just end in tears!!

The char* route is not as bad, but as char = byte, you're just saying you're going to treat the struct's data as bytes (it still can't be treated as a null terminated string)

Neither actually converts the struct to a string.

Andy
Last edited on Nov 20, 2011 at 12:39am
Nov 20, 2011 at 2:02am
Neither actually converts the struct to a string.


Not a meaningful string, no, but then there is no general way to convert a struct to a string. It does convert it to a completely legal string :)
Nov 20, 2011 at 2:08am
To me a legal string is a series of printible chars (letter, number, punctuation, plus '\r', '\n', '\t', ... ending with a single '\0'. That is not what will happen if you randomly cast emory to a "string".

As there is no general way to convert to a string, you need to write you own conversion routine, akin to ltoa() which - as you no doubt know - converts a long to a string. Unlike (char*)some_long_value!
Last edited on Nov 20, 2011 at 2:09am
Nov 20, 2011 at 9:59am
As Moschops said, there is no general way. If a specific question was asked, we could give a specific and meaningful solution. This is about as general as it can get so it could be scary indeed!
Nov 20, 2011 at 11:52am
How about serializing as a byte string?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
using namespace std;

struct Example
{
	int  index;
	char name[16];
	bool registered;
	bool suspended;
};

void dumpExample(ostream& os, const char* var_name, const Example& ex)
{
	os << "[Example : name = \"" << var_name << "\" size = " << sizeof(Example) << "]" << endl
	   << "- index      = " << ex.index      << endl
	   << "- name       = " << ex.name       << endl
	   << "- registered = " << ex.registered << endl
	   << "- suspended  = " << ex.suspended  << endl;
}

// wrap function with macro which uses stringizing operator
#define DUMP_EXPAMPLE(s, v) dumpExample(s, #v, v)

bool saveAsByteString(ostream& os, const unsigned char* pch, int size)
{
	bool ret = true; // in real code, there would be error handling!

	ostream::fmtflags old_flags = os.flags();
	char old_fill  = os.fill();

	os << hex << setfill('0');

	// could break line every 16/? bytes?
	for(int idx = 0; size > idx; ++idx)
	{
		if(0 < idx)
			os << ' ';
		// force output to use hex version of ascii code
		os << "0x" << setw(2) << static_cast<int>(pch[idx]);
	}

	os.flags(old_flags);
	os.fill(old_fill);

	return ret;
}

bool readAsByteString(istream& is, unsigned char* pch, int size)
{
	bool ret = true; // in real code, there would be more error handling!

	// get the line we want to process
	// could handle multi-line easy enough
	string line;
	getline(is, line); // error not handled, etc

	istringstream iss_convert(line);
	iss_convert >> hex;

	// read in unsigned ints, as wrote out hex version of ascii code rather
	// than the actual char (some of which would have been control
	// codes, etc)
	unsigned int u   = 0;
	int          idx = 0;

	while((iss_convert >> u) && (idx < size) && ret)
	{
		if((0x00 <= u) && (0xff >= u))
			pch[idx++] = static_cast<unsigned char>(u);
		else
			ret = false;
	}

	// if nothing went wrong in the loop, make sure we got the right
	// number of bytes.
	if(ret)
	{
		ret = iss_convert.eof() && (size == idx);
	}

	return ret;
}

// Test using stringstream as too lazy to code file reading...
void Test()
{
	bool ret = false;

	const Example ex = {
		11,        // index;
		"Tintin",  // name
		true,      // registered;
		false      // suspended;
	};

	cout << "Start:" << endl
		 << endl;
	DUMP_EXPAMPLE(cout, ex);
	cout << endl;

	ostringstream oss;

	cout << "=> saveAsByteString()" << endl;
	ret = saveAsByteString(oss, reinterpret_cast<const unsigned char*>(&ex), sizeof(Example));
	cout << endl;

	if(ret)
	{
		cout << "Ok!" << endl
			 << endl;

		string result = oss.str();
		// to force failure
		//result += " 0x66 0x60"; // too long
		//result.resize(result.length() - 4); // too short
		// Note: if you loose only a bit of the last byte
		// e.g. 0xC cf 0xCC then error is not detected.
		// Prob need to write the lenth of the string to file
		// so can check it's all read back. Or use explicit
		// markers for begin and end of data?

		cout << "Result:" << endl
			 << endl
			 << result << endl
			 << endl;

		istringstream iss(result);

		Example chk = {0};

		cout << "=> readAsByteString()" << endl;
		ret = readAsByteString(iss, reinterpret_cast<unsigned char*>(&chk), sizeof(Example));
		cout << endl;

		if(ret)
		{
			cout << "Ok!" << endl
				 << endl;

			cout << "Do structs match? = " << (0 == memcmp(&ex, &chk, sizeof(Example))) << endl
				 << endl;

			cout << "Check:" << endl
				 << endl;
			DUMP_EXPAMPLE(cout, chk);
			cout << endl;
		}
		else
		{
			cerr << "Erk!" << endl
				 << "readAsByteString failed?" << endl;
		}
	}
	else
	{
		cerr << "Erk!" << endl
			 << "saveAsByteString failed?" << endl;
	}

	cout << "Done." << endl;
}

int main()
{
	cout << boolalpha;

	Test();

	return 0;
}


The results for VC++2008 are:

Start:

[Example : name = "ex" size = 24]
- index      = 11
- name       = Tintin
- registered = true
- suspended  = false

=> saveAsByteString()

Ok!

Result:

0x0b 0x00 0x00 0x00 0x54 0x69 0x6e 0x74 0x69 0x6e 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x01 0x00 0xcc 0xcc

=> readAsByteString()

Ok!

Do structs match? = true

Check:

[Example : name = "chk" size = 24]
- index      = 11
- name       = Tintin
- registered = true
- suspended  = false

Done.


Last edited on Nov 20, 2011 at 12:45pm
Dec 1, 2011 at 7:53am

http://yaml.org/


never used it hough.
Topic archived. No new replies allowed.