DSP编程中的字节对齐
2019-07-13 09:55发布
生成海报
从PC上向ADI DSP平台移植时,经常会出现一些问题,其中很多问题和字节对齐有关。这类问题往往在PC上测试成功,在DSP上也能成功编译链接,但是运行却会出错,导致这类问题很难查出并解决。
问题成因:
我使用的是ADI的Blackfin系列DSP,不知道其他平台是否有这个规定。就是char型数据类型地址可以任意,short型数据类型地址必须被2整除,int型数据类型地址必须被4整除,依此类推,即基础数据类型的地址必须被这种数据类型的大小整除。
而一般PC上是没有这个规定的。于是问题来了,比如下面的取数据函数,在PC上没有问题,在ADI
DSP上运行肯定会出错的。
void get_data(unsigned char *inbuf)
{
char data1;
short data2;
int data3;
data2 = *(((short *)inbuf)++);
//1
data1 = *(inbuf++);
//2
data3 = *((int *)inbuf);
//3
fprintf(stdout, “data1 = %d/ndata2 = %d/ndata3 = %d/n”, data1, data2, data3);
return;
}
根据上面的规定,显然不论输入的inbuf地址是多少,上面的程序都会出错。比如说inbuf是奇数,句1就是将一个奇数地址强制转换成了一个short型地址,出错。如果inbuf是偶数,经过句1和句2后,句3显然又将一个奇数地址强制转换成了一个int型的地址,出错。
这种问题不是我特意设置来钻牛角尖的,他普遍存在于从码流中读入不同类型的数据的程序中,比如音视频解析对码流的解析,码流中存在各种数据类型的语法元素,将他们读入内存的时候就有这种问题。
解决方法:
方法1:
将一个长数据类型,分解成几个char类型来读取,比如一个int型的数据可以这样读取:
//original
unsigned char* inbuf; //注意一定是unsiged
unsigned int tmp1, tmp2, tmp3, tmp4;
int res;
tmp1 = (unsigned int)*(inbuf++);
tmp2 = (unsigned int)*(inbuf++);
tmp3 = (unsigned int)*(inbuf++);
tmp4 = (unsigned int)*(inbuf++);
res = (int)((tmp1 & 0xff) + ((tmp2 & 0xff)<<8) + ((tmp3 & 0xff)<<16) + ((tmp4 & 0xff)<<24));
//or macro
#define GetUnalignedDword( pb, dw ) /
(dw) = ((unsigned int) *(pb + 3) << 24) + /
((unsigned int) *(pb + 2) << 16) + /
((unsigned int) *(pb + 1) << 8) + *pb;
方法2:
定义一个包含基础数据类型的紧缩的结构体,将不对齐地址强制转化成此结构体,示例如下
#ifdef __GNUC__
#define GNUC_PACKED __attribute__ ((packed))
#else
#define GNUC_PACKED
#endif
#ifdef __arm
#define ARM_PACKED __packed
#else
#define ARM_PACKED
#endif
#if defined WIN32 || defined VDSP
#pragma pack(1)
#endif
ARM_PACKED struct unaligned_32 { unsigned int data; } GNUC_PACKED;
#if defined WIN32 || defined VDSP
#pragma pack()
#endif
//struct defined upper
int data;
data = ((struct unaligned_32 *)inbuf)->data;
方法2节省一些计算,不过一般来说码流解析不是主要占用系统资源的模块,不需要很高的效率。建议两种方法都可以试试,再根据实际的效果来选取效果最好的。
参考文章:http://blog.csdn.net/fmddlmyy/archive/2008/07/16/2663481.aspx
附:声明对齐数据类型的方法(摘自ffmpeg)
#if defined(__ICC) || defined(__SUNPRO_C)
#define DECLARE_ALIGNED(n,t,v)
t v __attribute__ ((aligned (n)))
#define DECLARE_ASM_CONST(n,t,v)
const t __attribute__ ((aligned (n))) v
#elif defined(__GNUC__)
#define DECLARE_ALIGNED(n,t,v)
t v __attribute__ ((aligned (n)))
#define DECLARE_ASM_CONST(n,t,v)
static const t v attribute_used __attribute__ ((aligned (n)))
#elif defined(_MSC_VER)
#define DECLARE_ALIGNED(n,t,v)
__declspec(align(n)) t v
#define DECLARE_ASM_CONST(n,t,v)
__declspec(align(n)) static const t v
#else
#define DECLARE_ALIGNED(n,t,v)
t v
#define DECLARE_ASM_CONST(n,t,v)
static const t v
#endif
ffmpeg中DECLARE_ALIGNED宏只用于数据类型和数组,我认为他的作用在于将数据或数组的首地址按照参数n来对齐,n单位为byte。至于他能否用于结构体,我不知道……估计也是可以的。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮