0

I have some trouble to get my float value out of a QVariant.

I call a function, which returns a QVariant, but when I convert it to a float value, like this:

float resf = result.toFloat();

The result is always 0.0000000. That's not the result I expect.

The QVariant itself is not empty:

QVariant to float

It contains the data I need.

When I take the last hexadecimal values and feed them to an IEEE 754 Converter, I got the result I expected:

0x411a8ad8 = 9.658897
  1. Why is result not the one I expected? (Because each element in QVariant can store 2-Bytes e.g. 0x0041, so the conversion failed?)
  2. How do I get my float value?

Edit1: After goug's suggestion:

bool convert = false;
convert = result.canConvert<float>();         =>true
QVariant::Type type = result.type();          =>ByteArray
QString str_typename = result.typeName();     =>QByteArray

But the results are still the same:

QByteArray ba = result.toByteArray();
float fl = ba.toFloat();                      =>fl = 0.00000000000

Edit2: After aatwo's suggestions:

bool bValid = true;
result.toFloat(&bValid);    =>bValid = false
bValid = true;
ba.toFloat(&bValid);        =>bValid = false  

So, both conversions failed, even "canConvert" returns "true".

Trying:

QByteArray floatByteArray = result.toByteArray();
float floatValue = *(float*)(floatByteArray.data());

also returns not the value I expected:

QByteArray To Float

But I get it working:

quint32 temp = ((char)ba[0] << 24) + ((char)ba[1] << 16) + ((char)ba[2] << 8) + (char)ba[3];
float* out = reinterpret_cast<float*>(&temp);   =>out = 9.658897

Thanks!

snucker
  • 31
  • 1
  • 7
  • Try inspecting the results of QVariant::type() and QVariant::canConvert(). Despite your inspection of the raw data, my guess is that QVariant doesn't know that it has something that can be converted to a float. – goug Nov 04 '16 at 22:38
  • If you use the QVariant::toFloat(bool*) overload does the bool indicate success or failure? Sounds like its probably failing, possibly because the variant does not contain a float type. In that second snippet of code it looks like the underlying data type is actually a QByteArray in which case you need to know how the float is stored, for example is it fundamentally a string representation of the float? Or the raw float data? – aatwo Nov 04 '16 at 23:55
  • 1
    Show the code to the variant-returning function. It's broken. That's where the problem is. Not in the code you show. – Kuba hasn't forgotten Monica Nov 05 '16 at 02:05
  • 1
    @KubaOber I can't provide the code. It is an interface to a COM object. – snucker Nov 05 '16 at 10:43
  • A COM object that can't return a float by value? What were they thinking :( – Kuba hasn't forgotten Monica Nov 05 '16 at 20:25

3 Answers3

4

According to the information provided the float value is being stored in its raw data form inside a QByteArray inside a QVariant.

Firstly it is worth noting that it would be much simpler and easier to store the float value inside the QVariant as a float type. Not only would this make your code simpler but it would also circumvents possible cross platform issues relating to data conversion and platform endian-ness.

Regardless, you should be able to extract your float value from your variant by doing something like the following:

QByteArray floatByteArray = floatVariant.toByteArray();
float floatValue = *(float*)(floatByteArray .data());

Also note: In your extra snippet of code you attempted to use the QByteArray::toFloat function to convert your QByteArray data to a float. You should be aware that this function only works for string representations of floats, not for use in situations like yours where your QByteArray contains the raw float data. QByteArray::toFloat and QVariant::toFloat both have optional bool parameters to indicate a conversion success / failure. Worth using to help notice issues like this!

aatwo
  • 948
  • 6
  • 12
  • The data comes from a COM function (return type VARIANT). Qt provides the data as QVariant, nothing I can do about it. I tried your suggestion (see first post), but I can't get the result as expected. Nevertheless you point me in the right direction, I found a very similar way, as you suggested (see also first post). Thanks for you help! – snucker Nov 05 '16 at 11:06
2

Here is my final solution, with all the informations I have gathered here.

QVariant result = pDatapoint->property("RawValue");
QByteArray ba = result.toByteArray();
quint32 temp = ((char)ba[0] << 24) + ((char)ba[1] << 16) + ((char)ba[2] << 8) + (char)ba[3];
float result_float;
std::memcpy(&result_float, &temp, sizeof(float));
snucker
  • 31
  • 1
  • 7
2

It's possible to do using 'value' method, descripted here.

QVariant valQVar={12.22f};
float valFloat = valQVar.value<float>();

Also, for several types, you can call methods such as

 valQVar.toBool();
 valQVar.toChar();
 valQVar.toDouble();

And so on. All functions are in documentation.

PolyGlot
  • 740
  • 6
  • 11