Solved Qt analog to C struct?
-
Hi -
My app uses a message header of a fixed size. I'd intended to do this:
struct { QByteArray hmac = QByteArray(32, '\0'); QByteArray iv = QByteArray(16, '\0'); QByteArray username = QByteArray(100, '\0'); QByteArray password = QByteArray(100, '\0'); QByteArray nonce = QByteArray(16, '\0'); uint8_t timestamp[23]; uint8_t reserved[1]; } msgHeader;
But I seem to get pointers to the QByteArrays in the structure, so this might not be the right approach.
Is there a Qt data structure that allows me to do this, or should I just keep all the fields as uint8_t, and convert to/from QByteArrays for processing?
-
@mzimmers said in Qt analog to C struct?:
But I seem to get pointers to the QByteArrays in the structure, so this might not be the right approach.
Rightfully so.
QByteArray
uses implicit sharing and is the size ofvoid *
the actual data is kept in the private object.Is there a Qt data structure that allows me to do this
No.
or should I just keep all the fields as uint8_t
Yes, or use
qint8
(they're aliases)convert to/from QByteArrays for processing
Attach a
QByteArray
to the data without copying it. UseQByteArray::fromRawData
for this and then pass it on for processing.PS:
@Wieland also suggested, rightfully so, to use std::array instead in this case. -
I'm not sure I understand...what should I use std::array for exactly?
-
std::array
is a thin wrapper (template) around a statically sized array of a given type. So you could use it instead ofint[]
, for example:struct { // ... std::array<uint8_t, 23> timestamp; std::array<uint8_t, 1> reserved; } msgHeader;
-
As a replacement for the QByteArrays and the C-style array:
struct MsgHeader { std::array<uint8_t, 32> hmac = {}; // ... std::array<uint8_t, 23> timestamp = {}; };
-
@Wieland OK. What is the advantage of this -- automatic range checking or some other safeties?
-
yes, also somewhat more type-safe as it does not decay readily to
void *
, is a C++ object ... and, well, the cool kids are using it (not that I approve, but that's whole other rant) ... ;) -
Yes, automatic range checking, increased safety against unintentional pointer mistakes, and compared to QByteArray, increased performance.
-
OK, thank you both.
-
Lot of cross-posting going on here ^_^
-
Twice in less than 10 minutes, must be a forum record or something.
-
Just to pursue this a little further, if I do use the std::array template, can I still do a memcpy, or do I have to assign the elements individually? I couldn't see anything in the cPPreference page on this.
Also, would it be better just to create one large QByteArray and use pointers to access delimited areas within it? (I'm still a little surprised that Qt doesn't have some construct to handle this).
-
@mzimmers said in Qt analog to C struct?:
can I still do a memcpy
The correct way to copy the array is to use
std::copy
. It's up to the implementation of your standard library to then find the fastest way to copy your data. -
@mzimmers said in Qt analog to C struct?:
if I do use the std::array template, can I still do a memcpy
Yes,
std::array
is an aggregate (means it has only one member that is your regulartype[]
array). Although(!), you should copy it like any other object - it is an object after all.Also, would it be better just to create one large QByteArray and use pointers to access delimited areas within it?
And throw away type safety? Why? There's no significant difference between that and having a struct containing fixed sized arrays.
I'm still a little surprised that Qt doesn't have some construct to handle this
To handle what exactly?
-
@mzimmers said in Qt analog to C struct?:
Also, would it be better just to create one large QByteArray and use pointers to access delimited areas within it?
I don't see why you would do that. Just complicates your code for no reason.
-
I'm just looking for a clean way to handle a data structure. In all candor, both the memcpy_s and the std::array/std::copy approaches are tough on the eyes. I guess, though, that's the price you pay to avoid overrunning boundaries.
-
I don't follow, perhaps I'm missing something. Suppose you use
std::array
. It'd look something like this:struct X { std::array<int, 4> a; std::array<double, 2> b; };
You use it as any POD struct.
X x = { { 1, 2, 3, 4 }, // This is an initializer list for std::array<int, 4> { 0.1, 12.3 } // The second member's intialization }; X y = x; // This is all, copying of the arrays is taken care for you by the STL and the compiler double z[2]; std::memcpy(z, x.b.data(), x.b.size()); // and voila, we copied the data to `z`
-
I'm probably being too fussy, but given how easily one can assign/copy QByteArray and QString objects, it's a shame IMO that there's no way to aggregate them as in a C struct. But it's probably their very flexibility that makes such use unfeasible.
It's OK...I'm content to use memcpy_s, but it's just not attractive code.
-
@Wieland said in Qt analog to C struct?:
Yes, automatic range checking,
You said this in response to why
std::array
should be used/preferred. What "automatic range checking" are you saying it provides, under what circumstances? -
@mzimmers said in Qt analog to C struct?:
I'm probably being too fussy,
Not really, but it would help to know what you dislike about the above example and why you think you need to use
memcpy
?@JNBarchan said in Qt analog to C struct?:
What "automatic range checking" are you saying it provides, under what circumstances?
std::array<int, 3> x; int z = x[3]; //< Regular arrays allow this (generally) x[3] = 0; //< Regular arrays mostly allow this too
e.g. run this through your debugger:
int main(int argc, char ** argv) { int z[2]; z[2] = 0; }