2009-05-01 15 views
4

Ich möchte einen FourCC Wert in C++, d. H. Eine vorzeichenlose 4-Byte-Ganzzahl.Setzen Sie einen FourCC-Wert in C++

Ich nehme an, der offensichtliche Weg ist ein #define, z.

#define FOURCC(a,b,c,d) ((uint32) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a))) 

und dann:

uint32 id(FOURCC('b','l','a','h')); 

Was ist die eleganteste Art und Weise können Sie denken, dies zu tun?

+0

Was, wenn ich etwas tun wollte wie: uint32 id (FOURCC ("blah")); – Nick

+0

Oder: FourCC id ("blah"); – Nick

+0

Verwendet dies OpenCV überhaupt? – scorpiodawg

Antwort

1

Ich sehe nichts falsch mit Ihrem Algorithmus. Aber für so etwas würde ich einfach eine Funktion anstelle eines Makros schreiben. Makros haben viele versteckte Funktionen/Probleme, die Sie im Laufe der Zeit beißen können.

uint FourCC(char a, char b, char c, char d) { 
    return ((uint32) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a))); 
} 
+1

Funktionen können nicht als Kompilierzeitkonstanten verwendet werden. Das bedeutet, dass Schalteranweisungen mit einer Funktion nicht möglich sind. Entweder ein Makro oder eine Template-Klasse (mit einem statischen const int oder enum für das Ergebnis, aber keine Funktion) sollte in Ordnung sein. – Tom

5

oder das gleiche mit einer Inline-Funktion

inline uint32_t FOURCC(uint8_t a, uint8_t b, uint8_t c, uint8_t d) 
{ 
    return ((uint32) (((d)<<24) | (uint32_t(c)<<16) | (uint32_t(b)<<8) | uint32_t(a))) 
} 

und die Kopfschmerzen eines Makros vermeiden, aber ansonsten Ihr Ansatz sieht für mich in Ordnung.

+0

Ich würde die zusätzliche Paranthese in der Funktionsversion verlieren. :) –

+1

Der größte Nachteil ist, dass Sie keine Inline-Funktion für eine Case-Anweisung in einem Switch-Block verwenden können. Entweder würde dafür eine Template-Struktur oder ein Makro funktionieren. – Tom

0

Anstatt eine #define, würde ich wahrscheinlich so ziemlich den gleichen Code und auf den Compiler setzen, um es zu inline.

15

Sie können es machen ein Compiler-Konstante verwendet:

template <int a, int b, int c, int d> 
struct FourCC 
{ 
    static const unsigned int value = (((((d << 8) | c) << 8) | b) << 8) | a; 
}; 

unsigned int id(FourCC<'a', 'b', 'c', 'd'>::value); 

Mit einem wenig zusätzlichen Aufwand, können Sie es bei der Kompilierung machen überprüfen, dass jede Zahl übergeben ist zwischen 0 und 255

+0

sehr schön, wenn der Wert zur Kompilierzeit konstant ist +1 –

+0

Ok, das ist mehr intesting. :) – Nick

+0

Jeder Nicht-Spielzeug-Compiler wird das Makro zur Kompilierzeit konstant falten. – Dave

3

Wenn ich mich nicht irre, können Sie einfach Multi-Character-Charakter-Konstanten für das Recht verwenden?

unsigned int fourCC = 'blah'; 

Dies ist perfekt durch die ANSI/ISO-Spezifikation gültig, obwohl einige Compiler ein wenig beschweren werden. So wurden Ressourcentypen in den älteren Macintosh-APIs verwendet.

+1

Ich denke, dass diese Implementierungen definiert sind und nicht unbedingt portabel sind. –

+2

Mit anderen Worten, Sie können nicht sicher sein, wo das 'b' enden wird, High-Order-Byte oder niedriger Ordnung. –

+0

Außerdem denke ich, dass einige Compiler das 'blah' als ein Byte und nicht als eine 32-Bit-Ganzzahl interpretieren können. Ich denke, der Standard sagt, es sollte als Int interpretiert werden. – Nick

1

Unter der Annahme, dass Windows (wie FOURCC ist ein Windows-Konzept), bietet die Win-API bereits mmioStringToFOURCC und mmioFOURCC.

+0

Danke. mmioFOURCC ist ein Makro, das auf das gleiche #define erweitert wird, das ich oben habe. – Nick

1

Wenn eine Kompilierung-Konstante nicht erforderlich ist, vielleicht die sauberste ist

unsigned int FourCCStr(const char (&tag)[5]) 
{ 
    return (((((tag[3] << 8) | tag[2]) << 8) | tag[1]) << 8) | tag[0]; 
} 

#define FOURCC(tag) FourCCStr(#tag) 

unsigned int id(FOURCC(blah)); 

Diese Tags nur vier Zeichen akzeptiert, je nach Bedarf.

+0

Oder: typedef char tag [5]; uint32 FourCC (const tag & t); – Nick

8
uint32_t FourCC = *((uint32_t*)"blah"); 

Warum nicht das?

BEARBEITEN: int -> uint32_t.

Und nein, es wird kein Char ** zu uint32_t. Es wirft ein (char *) nach (uint32_t *) und dereferenziert das (uint32_t *). Es gibt keine Endian-Ness, da es ein uint32_tto einem uint32_t zuweist. Die einzigen Defekte sind die Ausrichtung und das habe ich nicht ausdrücklich als 32bit-Typ angegeben.

+1

Da der Wert zwischen Big-und Little-Endian Maschinen variiert. Auf einigen Architekturen, die möglicherweise falsch ausgerichtet sind, was zu einer Hardware-Ausnahme zur Laufzeit. – Tom

+0

Ich hatte diesen Weg in Betracht gezogen und ich glaube, es würde funktionieren alle Plattformen, die wir unterstützen.Keiner der Vorschläge befasst sich mit Endianess. TBH dies ist kein Problem, da es plattformspezifische Daten sein wird. – Nick

+0

@ James Hopkin: Dies konvertiert nicht den Zeiger zu einem int, es konvertiert den Zeiger zu einem int POINTER, dann dereferenziert es.Der Wert wird immer gleich enden, als ob Sie eine Union zwischen 4 Zeichen und einem int verwendet hätten und die Zeichen an {'b', 'l', 'a', 'h'} zugewiesen hätten. Zum Thema Endianess sollten FOURCC-Codes in der gleichen Reihenfolge im Speicher sein (http://msdn.microsoft.com/en-us/library/dd375802(VS.85).aspx spielt darauf an, wenn es wenig Endianess erwähnt) auf Windows-Plattformen) –

-1
uint32 fcc(char * a) 
{ 
    if(strlen(a) != 4) 
     return 0;  //Unknown or unspecified format 

    return 
    (
      (uint32) 
      ( 
       ((*(a+3))<<24) | 
       ((*(a+2))<<16) | 
       ((*(a+1))<<8) | 
       (*a) 
      )  
    ); 
} 
+0

strlen ?! Sorry, ich wa Dies ist eine Kompilierzeitberechnung. – Nick

0

Wie wäre:

#if BYTE_ORDER == BIG_ENDIAN 
#define FOURCC(c0,c1,c2,c3) ((uint32) ((((uint32)((uint8)(c0)))<<24) +(((uint32)((uint8)(c1)))<<16)+ (((uint32)((uint8)(c2)))<<8) + ((((uint32)((uint8)(c3)))))) 
#else 
#if BYTE_ORDER == LITTLE_ENDIAN 
#define FOURCC(c3,c2,c1,c0) ((uint32) ((((uint32)((uint8)(c0)))<<24) +(((uint32)((uint8)(c1)))<<16)+ (((uint32)((uint8)(c2)))<<8) + ((((uint32)((uint8)(c3)))))) 
#else 
#error BYTE_ORDER not defined 
#endif 
#endif 
1

Durch die Verwendung von C++ 11 constexpr Sie so etwas wie schreiben:

constexpr uint32_t fourcc(char const p[5]) 
{ 
    return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 
} 

Und dann verwenden Sie es als:

fourcc("blah"); 

Profis:

  • lesbare,
  • , wenn das Zeichenfolge Argument bei der Kompilierung bekannt ist, dann wird die Funktion bei der Kompilierung (keine Laufzeitoverhead) ausgewertet.
  • hängt nicht von der Endianität ab (d. H. Das erste Zeichen des Arguments befindet sich immer im höchstwertigen Byte der Fourcc).

Nachteile:

  • erfordert C++ 11 (oder höher) Compilers.
Verwandte Themen