0

I'm working with Qt and C++. I have to manage error codes of an electronic board. I can get these errors in the form of QByteArray that I have to convert into a QVariant. I did not find any practial method to do this (so if you have one I'm here listening).Anyway, trying to convert it (the QByteArray) to the QVariant, the only method I found is to use a code like this:

QByteArray value;     //This is the QByteArray where I have the error code
QVariant qVariantOut; //This is the QVariant where I want to put the error
qVariantOut = QVariant(*(quint64*)(void*)(&(value).data()[0]));

Because of the bad casting steps I used, I have stumbled upon the various good casting rules and I did somethig like this:

qVariantOut =  QVariant(*(static_cast<quint64*(static_cast<void*>((&(value).data()[0]))));

These casts seem to work and so I decided to deepen the casting subject but I don't understand some results I got. Following I present all the cases I have tried. If someone could give me an explanation (I'll present mine) of what is happening in each case it would be great.

  1. qVariantOut = QVariant(*((quint64 *)value.data())); I think this works because value.data() returns a char* and the cast quint64* do a reinterpret_cast (if I interpreted well what it is said here: When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used? ). Is this reason correct?

  2. qVariantOut = QVariant(*(static_cast<quint64*>(value.data()) )); This one does't work because I'm trying to do a static_cast directly to an quint64*. But here I have one question: why it is not possible to cast from char* to quint64*. Aren't them some basics (POD) type for which a static_cast have to be possible?

I would like to understand better these casts... I even find someone that said: "if you need to cast pointers, cast them via void*". Comments?

  1. qVariantOut = QVariant( (quint64*)(value.data()) ); This is something like a bonus. I'm trying with this code to put in a QVariant a pointer... This give me the error "QVariant::QVariant(void) is private within this context*" and I don't get what this means.

Thank you.

EDIT: For the users that said it could be an XY problem. Here are some more information. I wrote a function to get variables from an electronic board. These variables could be QString, quint64, qint32, quint8 and so on...In my function, in order to get these variables, I use an external function (coming from an external library, developed internally by the electronic division of my company, I have to use it but can't modify it). In order to use this external function I need to pass as parameters: the variable I want to read (i.e.: errors, warnings, temperatures, version of firmware...), an output QByteArray and the size of the variable I want to read(for example errors->sizeof(quint64), temperatures->sizeof(quint8)). This external function, as you understand, returns a QByteArray.

The fact that I present the code with a cast to quint64 is only a case of my function.

I want to convert this QByteArray to a QVariant so my function can return this qVariantOut that I will convert to the correct variable (for example: I know that I need to read the error variable of the board, I call my function that will set the variable size and pass it to the external function (together with the variable name) that will return a QByteArray. This QByteArray will be converted in a QVariant returned outside my function. Outside I will convert the QVariant to the right variable for example a quint64 for the errors, using QVariant methods). Note that I do this because of the constraint of the system (I need to use that external function that returns always a QByteArray for every type of variable I want to read) and because I did not find a better and more practical method to convert a QByteArray to the final variable (ex.: if I use qba.toLongLong, with qba a QByteArray, it doesn't work)... if you have one, as I said before, I'm here listening to you.

Anyway I don't want to focus too much on the XY problem (but if it is an XY problem I want to resolve it obviously) but I want to understand better that casting rules and to have a constructive discussion on my doubt and questions :)

Community
  • 1
  • 1
iLeW
  • 59
  • 10
  • 1
    *that I have to convert into a QVariant* why exactly do you need to? (This post smells like a [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)) – peppe Feb 04 '16 at 19:46
  • 1
    Definitely an XY problem. I can almost guarantee if you say what you actually want to accomplish clearly, i can be done without any casts at all. To start with, what is an error code? A string? An 8-bit value? A 32-bit integer? Your code makes it look like error codes are a 64-bit signed integer, but that seems dubious. – ScottG Feb 04 '16 at 20:26
  • I made an EDIT explaing in more details my situation :) peppe and @ScottG – iLeW Feb 04 '16 at 22:22

1 Answers1

1

With your updates, this isn't quite as crazy as it first seemed. It is kinda crazy that you have an internal API putting random variables into a QByteArray rather than something like QVariant which is exactly what it is made for, but I get that you are stuck with what you have.

You have two options:

  1. Cast, but there's no need to do anything complicated, just use reinterpret_cast. Casting to void* then back to something else with static_cast is the same thing as a reinterpret_cast, so you might as well just call reinterpret_cast to start with.

  2. memcpy(&target, byteArray.data(), sizeof(target)); This avoids the casting, but is almost as ugly. In theory, its a little safer in light of memory alignment issues (don't have to rely on the data in your QByteArray being the right alignment to reinterpret_cast). It also lets you hold on to the data as long as you want without risking the internal pointer in the QByteArray being reclaimed behind your back.

Note that both of these options only work with POD types, but I assume other than QString everything you're getting back is, and for QString you'd have to make a special case depending on the encoding (pretty simple if is ASCII/Latin1).

As for why you can't static_cast directly from char* to quint64*, that isn't a static_cast. You can't static cast between distinct types, only related types, like between base* and a class that derives from base. There's a good explanation of static_cast's limited use case in this answer by EdChum.

Community
  • 1
  • 1
ScottG
  • 773
  • 6
  • 18
  • I think that they used the QByteArray (instead of Qvariant) because that particular function it is used even for other purposes (in a lower level context). Anyway thank you for your answer. I've tried the 2nd. About the 1st, someone said to me that with the two static_cast I would catch cases where I try to cast pointers to different size... Do you agree? (Actually, I don't understand what that means) – iLeW Feb 08 '16 at 14:39
  • 1
    No doing two static_casts, one to void* then one to your target won't do anything in that regard. Additionally, as noted, static_cast doesn't even work for what you are trying to do. Once stuffed into a QByteArray, you lose all information about the size the original object was. – ScottG Feb 08 '16 at 17:23