2

I've got the following C++ code :

template <int isBigEndian, typename val>
struct EndiannessConv
{
    inline static val fromLittleEndianToHost( val v )
    {
        union
        {
            val   outVal __attribute__ ((used));
            uint8_t bytes[ sizeof( val ) ] __attribute__ ((used));
        } ;

        outVal = v;
        std::reverse( &bytes[0], &bytes[ sizeof(val) ] );

        return outVal;
    }

    inline static void convertArray( val v[], uint32_t size )
    {
        // TODO : find a way to map the array for (uint32_t i = 0; i < size; i++)
        for (uint32_t i = 0; i < size; i++)
            v[i] = fromLittleEndianToHost( v[i] );
    }
};

Which work and has been tested (without the used attributes). When compiling I obtain the following errors from g++ (version 4.4.1)

|| g++ -Wall -Wextra -O3 -o t t.cc
|| t.cc: In static member function 'static val EndiannessConv<isBigEndian, val>::fromLittleEndianToHost(val)':
t.cc|98| warning: 'used' attribute ignored
t.cc|99| warning: 'used' attribute ignored
|| t.cc: In static member function 'static val EndiannessConv<isBigEndian, val>::fromLittleEndianToHost(val) [with int isBigEndian = 1, val = double]':
t.cc|148| instantiated from here
t.cc|100| warning: unused variable 'outVal'
t.cc|100| warning: unused variable 'bytes'

I've tried to use the following code :

template <int size, typename valType>
struct EndianInverser { /* should not compile */ };

template <typename valType>
struct EndianInverser<4, valType>
{ 
    static inline valType reverseEndianness( const valType &val )
    {
        uint32_t    castedVal =
            *reinterpret_cast<const uint32_t*>( &val );
        castedVal = (castedVal & 0x000000FF << (3 * 8))
                | (castedVal & 0x0000FF00 << (1 * 8))
                | (castedVal & 0x00FF0000 >> (1 * 8))
                | (castedVal & 0xFF000000 >> (3 * 8));

        return *reinterpret_cast<valType*>( &castedVal );
    }
};

but it break when enabling optimizations due to the type punning.

So, why does my used attribute got ignored? Is there a workaround to convert endianness (I rely on the enum to avoid type punning) in templates?

skaffman
  • 398,947
  • 96
  • 818
  • 769
Raoul Supercopter
  • 5,076
  • 1
  • 34
  • 37
  • '__attribute__ ((used))' applies to functions rather than variables/struct members (AFAIK). Also, what's the '4' in struct EndianInverser<4, valType>? – Peter Hull Apr 19 '10 at 12:48
  • Well 4 is the size of valType (I'd like to use the same code for integers and floats). I use it before to specialize uppon element size. The documentation of gcc say that used apply to variables ( http://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Variable-Attributes.html#Variable-Attributes ), so I'm a bit lost here :-/ – Raoul Supercopter Apr 19 '10 at 13:18
  • True, I was relying on my memory and an older version (4.1.2!) of the compiler. I'm a bit confused why the attribute is needed since outVal and v are clearly used, and why the compiler says they aren't. Last thing, if you cast val to a char* in your second code segment, and swap bytes, does that work? – Peter Hull Apr 19 '10 at 14:41
  • possible duplicate of http://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c – kennytm Apr 19 '10 at 19:25
  • Interesting duplicate, I may use "safer" versions. – Raoul Supercopter Apr 19 '10 at 20:17

1 Answers1

2

I only have gcc 4.2.1 but if I get rid of the attribute ((used)) and give the union a name it compiles without warnings for me.

  inline static val fromLittleEndianToHost( val v )
  {
        union
        {
          val   outVal ;
          uint8_t bytes[ sizeof( val ) ] ;
        } u;

        u.outVal = v;
        std::reverse( &u.bytes[0], &u.bytes[ sizeof(val) ] );

        return u.outVal;
  }

From what I've read the 'union' technique works on gcc but is not guaranteed in the standard, the other 'reinterpret_cast' method is wrong (because of type aliasing). However I think this applies to C, not sure about C++. Hope that helps.

Peter Hull
  • 6,683
  • 4
  • 39
  • 48