Search code examples
c++c++11gccgcc-warning

xor'ing float value & general cast question concerning compiler output


Well, both questions are concerned towards my compiling output, since I try to remove all warnings..

To the first question:
I'm xor'ing float values, compiler output: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

inline float ClassXY::GetFloat(void) const
{
    uint32_t xored = *(uint32_t*)&m_pParent->m_Value.m_fValue ^ (uint32_t)this; // compiler warning for this line
    return *(float*)&xored;
}

m_pParent is a pointer to this class ClassXY *m_pParent;
m_Value is a var of a struct and m_fValue is defined as a float inside the struct.

Any idea how to get around the warning? (I know that I can disable the warning, but I have no idea to get a clean solution to it)

My second qustion would be:
The scenario is nearly the same though, only with int. Compiler is talking about information loss: warning: cast from ‘const ClassXY*’ to ‘uint32_t {aka unsigned int}’ loses precision [-fpermissive]
Without the -fpermissive compiler flag, I wouldn't be able to compile..

inline int ClassXY::GetInt(void) const
{
    return (int)(m_pParent->m_Value.m_nValue ^ (int)this); // compiler warning for this line
}

And again, any idea on how to fix this?
Or is it inpossible without warnings, what I'm trying to accomplish?

To give you all an idea what it is about: auto example = g_pClassXY->FindVar("example_var");
Then: float float_val = example->fValue; // direct access, value is wrong
To get the value right, the right approach would be: float float_val = example->GetFloat();

Thanks in advance!


Solution

  • To avoid a strict aliasing violation, the code could be:

    static_assert( sizeof(float) <= sizeof(uint32_t), "size problem" );
    uint32_t xored{};
    memcpy(&xored, &m_pParent->m_Value.m_fValue, sizeof xored);
    xored ^= reinterpret_cast<uint32_t>(this);
    
    float ret;
    memcpy(&ret, &xored, sizeof ret);
    return ret;
    

    However there are still some issues:

    • The code is ill-formed on a system where this is a 64-bit pointer.
    • The float values involved might be an invalid bit pattern for float, causing undefined behaviour.

    If your intent is to "encrypt" a float, then the encrypted value should be stored as uint32_t or a byte array, not as float.

    The first bullet point could be addressed by generating a random 32-bit mask for each instance, instead of using this; or using uintptr_t instead of uint32_t.