使用联合来解决编译器警告:取消引用类型双关指针将违反严格别名规则

问题描述 投票:0回答:1

以下代码会导致编译器警告:

取消引用类型双关指针将违反严格别名规则

#include <endian.h>

template <typename T>                                                 
inline T HostToLittleEndian(T val) {                                              
  switch (sizeof(val)) {                                                   
    case 1:                                                                
      return val;                                                          
    case 2: {                                                              
      uint16_t r = htole16(*reinterpret_cast<uint16_t*>(&val));                
      return *reinterpret_cast<T*>(&r);                                    
    }                                                                      
    case 4: {                                                              
      uint32_t r = htole32(*reinterpret_cast<uint32_t*>(&val));                
      return *reinterpret_cast<T*>(&r);                                    
    }                                                                      
    case 8: {                                                              
      uint64_t r = htole64(*reinterpret_cast<uint64_t*>(&val));                
      return *reinterpret_cast<T*>(&r);                                    
    }                                                                      
    default:                                                               
      static_assert(sizeof(val) <= 8, "Value is 64-bits or less.");        
  }                                                                        
}                                                                          

我能够使用

union
进行重构,这解决了编译器警告,但现在有
val
的额外副本。这个其他 StackOverflow 问题让我相信副本是不可避免的,这是真的吗?还是有我没有意识到的更优化的解决方案?

template <typename T>
inline T HostToLittleEndian(T val) {
  union {
    T value;
    uint64_t u64;
    uint32_t u32;
    uint16_t u16;
    uint8_t u8;
  } data;
  data.value = val;
  
  switch (sizeof(val)) {
    case 1:
      break;
    case 2:
      data.u16 = htole16(data.u16);
      break;
    case 4:
      data.u32 = htole32(data.u32);
      break;
    case 8:
      data.u64 = htole64(data.u64);
      break;
    default:
      static_assert(sizeof(val) <= 8, "Value is 64-bits or less.");
  }
  return data.value;   
}

注意,整型和浮点类型都是有效的 T 类型。

c++ compiler-errors casting endianness
1个回答
0
投票

提供

T
是一个整型,你实际上不需要强制转换,因为隐式转换应该可以正常工作,例如:

#include <type_traits>
#include <endian.h>

template <typename T>
inline T HostToLittleEndian(T val) {
  static_assert(std::is_integral<T>::value, "Value must be integral");
  switch (sizeof(val)) {
    case 1:
      return val;
    case 2: {
      return htole16(val);
    }
    case 4: {
      return htole32(val);
    }
    case 8: {
      return htole64(val);
    }
    default:
      static_assert(sizeof(val) <= 8, "Value must be 64-bits or less.");
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.