Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1518259
  • 博文数量: 114
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 1357
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-19 18:13
文章分类
文章存档

2010年(8)

2009年(9)

2008年(27)

2007年(62)

2006年(8)

我的朋友

分类: LINUX

2007-09-07 17:21:45

北京理工大学 20981 陈罡
相信做过嵌入式开发的朋友,都对字节对齐问题已经非常熟悉了。这次又是和老朋友打交道了,
不过整整浪费了偶一个上午的时间,才把图片解码库的字节对齐问题解决,现在可以支持
png,jpeg以及gif了,很是兴奋啊。
 
话说字节对齐引起的问题,其实归根究底就是c语言sizeof()引起的问题,很多DX已经有了很多
论述了,由于偶是moto a1200的开发,还是再聒噪一遍(毕竟浪费了偶不少时间),感觉太烦
的朋友大可略过不看。
 
问题描述:
typedef struct _RGB_COLOR_ {
    unsigned char r ;
    unsigned char g ;
    unsigned char b ;
} rgb_color ;
如果我们的编译器是align 8的,那么sizeof(rgb_color)的值为3,
如果编译器是align 16的,那么sizeof(rgb_color)的值为4
 
可不要小看了这1个字节的占位,在视频和图像文件处理和解析中,这一个字节可是致命的。
例如在gif文件解码库中的一段代码:
// Global colour map
if (dscgif.pflds & 0x80)
 fp->Read(TabCol.paleta,sizeof(struct rgb_color)*TabCol.sogct,1);
else
 bTrueColor++; //first chance for a truecolor gif

这里的Read会读入指定大小的数据,并且直接把数据读入到结构体中去。

我们已知TabCol.sogct的值为256,那么由于上面的原因,在symbian和pc上的linux(偶推崇的是
slackware 11.0在此鸡婆一下),都是没有问题的,都是属于sizeof()的值为3的常规情况。
但是好景不长,到了moto的a1200交叉编译环境下arm-linux-gcc version 3.3.6情况就不同了。
sizeof(struct rgb_color)的值为4,这下可好,一下子读取的时候偏移了256个字节,最终导致
所有的解析流程被打乱,整个数据解析也就错误了。
 
各位肯定更加关心,如果出现了这种情况该如何是好呢?
我们可以看下面一个简单的例子:
#include
#include
typedef struct _ABC_ {
  unsigned char r ;
  unsigned char g ;
  unsigned char b ;
}  ABC ; 
int main(int argc, char * argv[])
{
  ABC t ;
  printf("sz = %d\n", sizeof(t)) ;
  return 0 ;
}
我们用gcc t.c -o t来编译。你可以看到sz = 3。也就是pc上的gcc编译,它是按照字节对齐的。
修改结构体的字节对齐有很多方法,其中标准c++中的定义是:
#pragma pack(1)
typedef struct _ABC_ {
  unsigned char r ;
  unsigned char g ;
  unsigned char b ;
}  ABC ; 
#pragma pack()
代表一个字节对齐sz还是等于3,
 
如果是为a1200开发,采用的是gnu的编译器,那么可以试试下面
的方法(这个方法就是gcc传参数了):
typedef struct _ABC_ {
  unsigned char r ;
  unsigned char g ;
  unsigned char b ;
}  __attribute__((aligned(4))) ABC ;
这里的4代表4字节对齐,aligned就是传给gcc的参数了。此时编译上面的代码,就会看到sz的值
为4,也可以换别的参数再试试,呵呵,是不是很方便,不过这里的只能够gcc编译器用,什么
vc啦,bc啦,什么的就都没戏了。
 
最后一种,就是在编译的命令中下功夫,例如arm-linux-gcc就支持--pack-struct参数,该参数
用于结构体的按字节对齐的,
 
呵呵,实在不行再实验这个方法这样编译会有别的问题,比如文件a.cpp用这种方法编译,文件b.cpp
没有用这种方法编译,那么结果就未知拉。有可能同样的结构体,在a里面工作正常,但是如果希望把
a里面的数据通过该结构体传递给b.cpp,由于b.cpp的对齐方式不对,那么读取出来的数据肯定是错误的。
 
这样编译出来的就是按照字节对对齐的代码了:
$arm-linux-gcc t.c -o t --pack-struct
 
如果上面的代码直接编译:
$arm-linux-gcc t.c -o t
呵呵,sz的值就不同,这一点偶做gif解码的时候头大了好几圈,综合使用上面说的几个方法,
最终字节对齐问题就都可以解决的。
 
附a1200真机抓图:
 
阅读(3383) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~