一、MKTAG和MKBETAG宏定义分析
宏MKTAG和MKBETAG定义在FFmpeg源码(本文演示用的FFmpeg源码版本为5.0.3)的源文件libavutil/macros.h中:
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24))
MKTAG:将形参中的字符a,b,c,d转换为整形,按小端模式存贮。
MKBETAG:将形参中的字符a,b,c,d转换为整形,按大端模式存贮。
二、编写具体例子测试MKTAG和MKBETAG
编写测试例子main.c,在CentOS 7.5上通过10.2.1版本的gcc可以成功编译:
#include <stdio.h>
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24))
int main()
{
printf("0x%X\n",MKTAG('R', 'I', 'F', 'F'));
printf("0x%X\n",MKBETAG('R', 'I', 'F', 'F'));
return 0;
}
使用gcc编译,运行,输出如下:
本测试例子中,'R'的ASSIC值为0x52,'I'的ASSIC值为0x49,'F'的ASSIC值为0x46。
语句MKTAG('R', 'I', 'F', 'F') 将字符'R', 'I', 'F', 'F'转换为整形,按小端模式存贮,所以转换出来的整形为0x46464952。
语句MKBETAG('R', 'I', 'F', 'F') 将字符'R', 'I', 'F', 'F'转换为整形,按大端模式存贮,所以转换出来的整形为0x52494646。
三、通过MKTAG实现switch、case语句间接支持字符串匹配
MKTAG和MKBETAG宏定义在FFmpeg源码中的其中一个重要作用是:使C语言中的switch、case语句间接支持字符串匹配。老版本的C语言编译器switch、case语句中case的值必须是整数或字符常量。但配合MKTAG宏可以间接绕过这一限制。
有如下例子:
#include <stdio.h>
#include <string.h>
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
enum eType
{
TYPE1 = MKTAG('T', 'Y', 'P', '1'),
TYPE2 = MKTAG('T', 'Y', 'P', '2'),
TYPE3 = MKTAG('T', 'Y', 'P', '3'),
};
int main()
{
char strType[4] = "TYP2";
int nType = MKTAG(strType[0], strType[1], strType[2], strType[3]);
switch (nType) {
case TYPE1:
printf("TYPE1\n");
break;
case TYPE2:
printf("TYPE2\n");
break;
case TYPE3:
printf("TYPE3\n");
break;
default:
break;
}
return 0;
}
使用gcc编译,运行,输出如下:
从上述例子中,我们可以看到FFmpeg源码中其中一个C语言的设计艺术,通过MKTAG实现switch、case语句间接支持字符串匹配。