6

FourCC値、つまり符号なし4バイト整数をC++で設定したいと思います。

明らかな方法は#defineだと思います。例:

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

その後:

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

これを行うためにあなたが考えることができる最もエレガントな方法は何ですか?

4

12 に答える 12

17

次を使用して、コンパイル時の定数にすることができます。

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);

少し手間をかけるだけで、渡された各数値が 0 から 255 の間であることをコンパイル時にチェックできるようになります。

于 2009-05-01T13:41:07.737 に答える
10
uint32_t FourCC = *((uint32_t*)"blah");

なぜこれではないのですか?

編集: int -> uint32_t.

いいえ、char** を uint32_t にキャストしません。(char*) を (uint32_t*) にキャストし、(uint32_t*) を逆参照します。uint32_t に uint32_t を割り当てるため、エンディアンは関係ありません。唯一の欠陥はアライメントであり、32 ビット型を明示的に示していませんでした。

于 2009-05-01T14:46:38.903 に答える
6

C++11 constexpr を使用すると、次のように記述できます。

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

そして、次のように使用します。

fourcc( "blah" );

長所:

  • より読みやすく、
  • 文字列引数がコンパイル時にわかっている場合、関数はコンパイル時に評価されます (実行時のオーバーヘッドはありません)。
  • エンディアンに依存しません (つまり、引数の最初の文字は常に fourcc の最上位バイトになります)。

短所:

  • c++11 (またはそれ以降) のコンパイラが必要です。
于 2014-12-15T11:36:36.613 に答える
4

またはインライン関数で同じことを行います

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)) )
} 

マクロの頭痛の種を避けますが、そうでなければあなたのアプローチは私にはうまく見えます。

于 2009-05-01T13:37:56.620 に答える
3

私が間違っていなければ、その権利に複数文字の文字定数を使用できますか?

unsigned int fourCC = 'blah';

一部のコンパイラは少し文句を言うでしょうが、これはANSI/ISO仕様によって完全に有効です。これは、以前のMacintoshAPIでリソースタイプが処理されていた方法です。

于 2009-05-01T14:00:37.767 に答える
1

Windowsを想定すると(FOURCCはWindowsの概念であるため)、WinAPIはすでにmmioStringToFOURCCmmioFOURCCを提供しています。

于 2009-05-01T14:07:02.197 に答える
1

あなたのアルゴリズムには何の問題もありません。しかし、このようなものについては、マクロの代わりに関数を書くだけです。マクロには、時間の経過とともにあなたを噛む可能性のある多くの隠れた機能/問題があります。

uint FourCC(char a, char b, char c, char d) { 
  return ( (uint32) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)) );
}
于 2009-05-01T13:37:55.933 に答える
1

コンパイル時の定数が必要ない場合、おそらく最も適切なのは

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));

これは、必要に応じて 4 文字のタグのみを受け入れます。

于 2009-05-01T14:26:21.013 に答える
0

#defineではなく、おそらくほぼ同じコードを配置し、コンパイラーに依存してインライン化します。

于 2009-05-01T13:38:13.780 に答える
0

どうですか:

#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
于 2013-08-22T13:34:01.307 に答える
0

最近では、constexpr と c++17 を使用したより良い解決策があります (以前のことかもしれませんが、確かではありません)。完全にクロス プラットフォームかどうかはわかりませんが、Visual Studio と XCode で動作します。

まず、関数をコンパイル時の値に変換するためのラッパー関数が必要です。

template <class TYPE, TYPE VALUE> constexpr TYPE CompileTimeValue() { return VALUE; }

次に、短い文字列を整数に変換する constexpr 関数が必要です。

template <class UINT, UInt32 IS_LITTLE_ENDIAN> constexpr UINT MakeCCFromNullTerminatedString(const char * string)
{
    UINT cc = 0;

    UINT shift = 1;

    if (IS_LITTLE_ENDIAN)
    {
        shift = (sizeof(UINT) == 8) ? (0xFFFFFFFFFFFFFFull + 1) : 0xFFFFFF + 1;
    }

    while (UINT c = *string++)
    {
        c *= shift;

        cc |= c;

        if (IS_LITTLE_ENDIAN)
        {
            shift /= 256;
        }
        else
        {
            shift *= 256;
        }
    }

    return cc;
}

次に、マクロでラップして、4 バイトと 8 バイトの両方の文字定数を保持し、リトル エンディアンとビッグ エンディアンのバリアントを使用します (必要な場合)...

#define ID32(x) CompileTimeValue<UInt32,MakeCCFromNullTerminatedString<UInt32,0>(x)>() 
#define ID64(x) CompileTimeValue<UInt64,MakeCCFromNullTerminatedString<UInt64,0>(x)>()
#define CC32(x) CompileTimeValue<UInt32,MakeCCFromNullTerminatedString<UInt32,1>(x)>()
#define CC64(x) CompileTimeValue<UInt64,MakeCCFromNullTerminatedString<UInt64,1>(x)>()

確認するいくつかのテスト..

ASSERT(CC32("test") == 'test');

UInt32 v = CC32("fun");

UInt32 test;

switch (v)
{
case CC32("fun"):
    test = 1;
    break;

case CC32("with"):
    test = 2;
    break;

case CC32("4ccs"):
    test = 3;
    break;
}

境界のオーバーラン チェックは行われていませんが、おそらくコンパイル時のアサーションで追加できます。

于 2020-12-21T04:24:11.587 に答える
-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)
            )       
    );
}
于 2009-05-01T15:51:30.713 に答える