2016-05-22 10 views
2

Geschichte zu vereinfachen ein wenig lang ist, ist es eine Endian-Universal-Implementierung für ganze Zahl ist, ist die ursprüngliche Code wie zum Beispiel:Wie C++ 14.11 zu verwenden, um diese Umsetzung

#ifdef _BIG_ENDIAN_ 
#define ENDIANUSHORT(src)  (unsigned short)src 
#define ENDIANULONG(src)  (unsigned long)src 
#define ENDIANUINT64(src)  (unsigned long long)src 
#else 
#define ENDIANUSHORT(src)  ((unsigned short)((((src)>>8)&0xff) |\ 
               (((src)<<8)&0xff00))) 

#define ENDIANULONG(src)  ((unsigned long)((((src)>>24)&0xFF) |\ 
               (((src)>> 8)&0xFF00) |\ 
               (((src)<< 8)&0xFF0000) |\ 
               (((src)<<24)&0xFF000000))) 

#define ENDIANUINT64(src)  ((unsigned long long)((((src)>>56)&0xFF) |\ 
               (((src)>>40)&0xFF00) |\ 
               (((src)>>24)&0xFF0000) |\ 
               (((src)>> 8)&0xFF000000) |\ 
               (((src)<< 8)&0xFF00000000LL) |\ 
               (((src)<<24)&0xFF0000000000LL) |\ 
               (((src)<<40)&0xFF000000000000LL) |\ 
               (((src)<<56)&0xFF00000000000000LL))) 
#endif //_BIG_ENDIAN_ 

template< 
    typename T, 
    typename std::enable_if<std::numeric_limits<T>::is_integer>::type* = nullptr> 
T _endian(T& t) { 
if (sizeof(T) == 2) 
    return ENDIANUSHORT(t); 
else if (sizeof(T) == 4) 
    return ENDIANULONG(t); 
else if (sizeof(T) == 8) 
    return ENDIANUINT64(t); 

return t; 
} 

template<typename T> 
void endian(T& t) { t = _endian(t); } 

int main() 
{ 
    long lv = 123; 
    endian(lv); 
    ...... 
} 

Es funktioniert gut, aber es wie in MSVC sind Warnungen wie:

warning C4293: '>>': shift count negative or too big, undefined behavior 

Dann verfeinert er als: T _endian Ersetzen (T & t) mit dem folgenden Code definieren:

static int64_t _endian(int64_t t) { 
    return ENDIANUINT64(t); 
} 

static uint64_t _endian(uint64_t t) { 
    return ENDIANUINT64(t); 
} 

static int32_t _endian(int32_t t) { 
    return ENDIANULONG(t); 
} 

static uint32_t _endian(uint32_t t) { 
    return ENDIANULONG(t); 
} 

static int16_t _endian(int16_t t) { 
    return ENDIANUSHORT(t); 
} 

static uint16_t _endian(uint16_t t) { 
    return ENDIANUSHORT(t); 
} 

static int8_t _endian(int8_t t) { 
    return t; 
} 

static uint8_t _endian(uint8_t t) { 
    return t; 
} 

Jetzt ohne Vorwarnung, aber ich denke, es gibt zwei Nachteile:

  1. Die Funktionen Implementierung ist langweilig, überflüssig und inconcise.
  2. Vielleicht sind einige Fälle nicht

bedeckt denke ich C++ 14.11 einen eleganten und kurze Implementierungs es zu beenden zur Verfügung stellen kann, haben Sie eine Idee?

Danke.

+0

Sie können einen Blick in die Boost-Endian-Bibliothek haben wollen. –

+0

Danke für Ihre Information. Boost ist sehr berühmt, aber aus meiner Sicht, ich möchte nicht zusätzliche riesige Code-Basis-Implementierung einzuführen, also bin ich nicht die Fans von Boost. –

+0

Ich bin auch kein Fan von der Einführung von viel unnötigen Code. Schau mal, was sie gemacht haben ;-) –

Antwort

4

Sie brauchen nicht C++ 11/14 per se. Was Sie tun müssen, ist

  1. Ersetzen Sie diese Makros mit Inline-Funktionen. Das ist nicht nur mehr C++ sy, es erleichtert auch den nächsten Schritt.
  2. Machen Sie die Inline-Funktionen static constexpr Mitglieder in einer Traits Klasse. Akzeptieren von size_t der Ganzzahl als Vorlagenparameter.
  3. Implementieren Sie die Vorlage in Bezug auf die Merkmalsklasse.

Der Code:

template<std::size_t> struct EndianTraits; 

template<> 
struct EndianTraits<2u> 
{ 
    using type = std::uint16_t; 
#ifdef _BIG_ENDIAN_ 
    constexpr static type ToEndian(type val) { return val; } 
#else 
    constexpr static type ToEndian(type val) { return ((((val)>>8)&0xff) | 
                (((val)<<8)&0xff00))); } 
#endif 
}; 

template<typename T, 
     typename = std::enable_if<std::numeric_limits<T>::is_integer>::type> 
T Endian(T t) { 
    using type = EndianTraits<sizeof(T)>::type; 
    return EndianTraits<sizeof(T)>::ToEndian(static_cast<type>(t)); 
} 
+0

für # 1 und # 2, ich kann sie verstehen, aber sie sind nicht mein Fokus, wie für # 3, ich denke, es kann eine gute Lösung sein, kannst du mir schnell zeigen Beispiel? –

+0

@ ravin.wang, für kurze Ints hinzugefügt. Beachten Sie jedoch, dass # 1 und # 2 ein Muss sind, um # 3 zu machen. Außerdem sollten Sie Dinge im globalen Bereich nicht mit führenden Unterstrichen benennen. Diese Namen sind für die Implementierung durch den Standard reserviert. – StoryTeller

+0

Teller Vielen Dank für die Antwort, es scheint meine Frage zu lösen. um ehrlich zu sein, ich denke, der Code nicht so präzise ist, weil wir struct EndianTraits <2u>, struct EndianTraits <4u>, struct EndianTraits <8u>, struct EndianTraits <1u> oder struct EndianTraits <1>, struct EndianTraits <2>, struct EndianTraits <4>, struct EndianTraits <8> definieren –

Verwandte Themen