How do I copy the structure which has both string and integer into a char array in C++?

I want to generate hash of struct prop so for i need to copy the structure into a byte array and pass it to md5 function of openssl. I want to know how to copy struct prop which has another structure of string and some integer value into a char array. Please let me know if anyone has done this?

struct innerprop
{
string a;
string b;
string c;
}

struct prop
{
string id;
string name;
int p;
innerprop ip;
}
One terse way is to do something like this:

1
2
3
4
5
6
7
8
using u8 = std::uint8_t;
using u8_string = std::basic_string<u8>;

u8_string to_u8_string(std::string const& f)
{ return u8_string(reinterpret_cast<u8 const*>(f.c_str()), f.size()); }

u8_string serialize(prop const& p)
{ return to_u8_string(fp.id) + to_u8_string(p.name) /* ... */; }

But it does imply some overhead - which may or may not be swallowed by the time required to compute the digest.

Full example:
http://coliru.stacked-crooked.com/a/1ead2e262fc1d71e
Last edited on
You could maybe do something along these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void f(prop& pr)
{
    using ucp = unsigned char *;

    MD5_CTX mdContext;
    MD5_Init( &mdContext );

    MD5_Update( &mdContext, ucp(pr.id.c_str()),   pr.id.size() );
    MD5_Update( &mdContext, ucp(pr.name.c_str()), pr.name.size() );
    MD5_Update( &mdContext, ucp(&pr.p),           sizeof pr.p );
    MD5_Update( &mdContext, ucp(pr.ip.a.c_str()), pr.ip.a.size() );
    MD5_Update( &mdContext, ucp(pr.ip.b.c_str()), pr.ip.b.size() );
    MD5_Update( &mdContext, ucp(pr.ip.c.c_str()), pr.ip.c.size() );

    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5_Final( digest, &mdContext );

    // ...
}

dutch wrote:
You could maybe do something along these lines:

That is probably a better option than my suggestion.

(I didn't know about that API)
Last edited on
Thanks a lot for the solution, i will try this
md5 is a distinct calculation, so every md5 is the same as any other. If you are annoyed with the need to pass a text string to it, find one that accepts it as a byte-chunk eg digest = md5(char*, size in bytes) instead. Its an annoying, couple of page algorithm, but there are many, many examples of it online. Many are low performance; I had to tweak the one I found a lot.

if yours is in this format, you do not need to do anything at all.
digest = md5( (char *)(&structvar), sizeof(struct)); (it may also want unsigned char* ?? or it may not matter (the bits are the bits))
that may byte you on struct alignments if you are comparing your hash to one generated by someone else using another language or something, but if you can align and pad the bytes the same way, you will get the same digest out, so it may just be compiler flags to align it or something from there.
Last edited on
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
#include <iostream>
#include <string>
#include <cstring>

using namespace std;

typedef unsigned char BYTE;

struct innerprop
{
    string a;
    string b;
    string c;
}

struct prop
{
    string id;
    string name;
    int p;
    innerprop ip;
}

int main()
{
    BYTE *byte_array = new BYTE[sizeof(prop)];
    prop p;

    p.id = "hi";
    p.name = "hehe";
    p.p = 1542;
    p.ip.a = "A";
    p.ip.b = "B";
    p.ip.c = "C";

    memcpy( byte_array, &p, sizeof(prop) );

    // use byte_array
    // ...

    // free allocated memory
    delete[] byte_array;
}


if you are not gonna be writing to the byte_array then just
1
2
3
prop p;
BYTE *byte_array = reinterpret_cast<BYTE*>(&p);
// now you can pass byte_array to a function for processing 
Last edited on
Seems more likely that OP wants to hash the contents of the strings, rather than their object representations.

There is no need to allocate any memory, either.
Last edited on
@fewdiefie, I hope you're joking! :)

The data for the strings is (possibly! *) on the heap. All you would be serializing is the pointers and size information.

* small strings (perhaps 8 to 16 bytes) can be stored in the main structure of a string.

If you want to play with the memcpy-the-struct idea and it's problems:

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
#include <iostream>
#include <string>
#include <cstring>
using namespace std;

struct innerprop
{
    string a;
    string b;
    string c;
};

struct prop
{
    string id;
    string name;
    int p;
    innerprop ip;
};

void clear( prop& p )
{
#if 0
    p.id.clear();
    p.name.clear();
    p.p = 0;
    p.ip.a.clear();
    p.ip.b.clear();
    p.ip.c.clear();
#else
    p.id = "one";
    p.name = "two";
    p.p = 123456789;
    p.ip.a = "three";
    p.ip.b = "four";
    p.ip.c = "five";
#endif
}

void prn( prop& p )
{
    cout << "======================\n"
         << "id  : " << p.id   << '\n'
         << "name: " << p.name << '\n'
         << "p   : " << p.p    << '\n'
         << "ip.a: " << p.ip.a << '\n'
         << "ip.b: " << p.ip.b << '\n'
         << "ip.c: " << p.ip.c << '\n';
}

int main()
{
    prop p;
#if 0
    p.id = "hi";
    p.name = "hehe";
    p.p = 1542;
    p.ip.a = "Alpha";
    p.ip.b = "Beta";
    p.ip.c = "Gamma";
#else
    p.id = "hiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
    p.name = "hehe" "0123456789012345678901234567890123456789";
    p.p = 1542;
    p.ip.a = "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    p.ip.b = "Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
    p.ip.c = "Cccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
#endif

    prn(p);

    auto b = new char[sizeof p];
    memcpy( b, &p, sizeof p );

    clear(p);
    prn(p);

    memcpy( &p, b, sizeof p );    
    prn(p);

    delete[] b;
}

Last edited on
oh, he said char array in the title but used string; mine won't work with string either, of course. Should have looked closer.
Topic archived. No new replies allowed.