我希望在C++中设置一个FourCC值,即一个无符号的4字节整数。
我想最明显的方法是使用#define,例如:
#define FOURCC(a,b,c,d) ( (uint32) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)) )
然后:
uint32 id( FOURCC('b','l','a','h') );
你能想到最优雅的方式是什么?
我希望在C++中设置一个FourCC值,即一个无符号的4字节整数。
我想最明显的方法是使用#define,例如:
#define FOURCC(a,b,c,d) ( (uint32) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)) )
然后:
uint32 id( FOURCC('b','l','a','h') );
你能想到最优雅的方式是什么?
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之间。
uint32_t FourCC = *((uint32_t*)"blah");
为什么不能这样做?
编辑:int -> uint32_t。
而且它并没有将char **转换为uint32_t。它将(char*)转换为(uint32_t*),然后解引用(uint32_t*)。没有涉及字节序,因为它将一个uint32_t 赋值给另一个uint32_t,唯一的缺陷是对齐和我没有明确指定32位类型。
通过使用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" );
优点:
缺点:
(p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]
而不是(p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]
。 - Octo Poulosinline 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)) )
}
unsigned int fourCC = 'blah';
根据ANSI/ISO规范,这是完全有效的,尽管一些编译器可能会抱怨一点。这是旧版Macintosh API中处理资源类型的方式。
'a'
在 C++ 中是 char
类型,在 C 中则是 int
类型。 - bames53我认为你的算法没有问题。但是对于这样的情况,我会写一个函数而不是宏。宏有很多隐藏的特性/问题,随着时间的推移可能会让你吃亏。
uint FourCC(char a, char b, char c, char d) {
return ( (uint32) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)) );
}
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));
这只接受四个字符的标签,正如所需。
假设您使用的是Windows操作系统(因为FOURCC是Windows概念),Win API已经提供了mmioStringToFOURCC和mmioFOURCC。
这样怎么样:
#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