本文共 3487 字,大约阅读时间需要 11 分钟。
如下是自己在开发项目的时候遇到的一个问题,并简单地记录下来。讲解的思路不是很连贯,但是,其中有给出一个例子,该例子推理出了问题的所在。
问题的引出
在开发项目的时候,下位机把一包事件发送给上位机,那么,自己调试,在发送数据包的时候,把事件给显示出来,有如下的逻辑:
typedef unsigned char INT8U;
typedef unsigned long long INT64U;
struct _EVENT
{
INT64U cardid; //结构体中有这个数据
.....
};
INT8U buf[1204]; //存放事件包的缓存
memcpy(buf, .....); //把事件包存放到 buf[] 缓存中
void show_card_info(INT8U *buf, INT16U count) //显示缓存信息
{
Event *e = (Event*)buf; //把 buf 缓存强制转换为 Event* 类型
printf("e->cardid = %llu \n", e->cardid);
.....
}
最终,运行程序发现:
1 cardid 变量中 8 个字节存放的数据是正确的,但是,使用 printf(); 输出的时候,却是错误的。
2 假如 cardid 中 8 个字节的数据是 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88,而在 cardid 前面的 2 个字节是 0x1A, 0x1B 的话,那么,printf(); 输出的 carid 值是:0x1A, 0x1B , 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 这样的数据组织成的值。
就是说,cardid 的数值是 buf[ ] 中给 Event*e 引用的时候,会引用其前面的2 个字节。
注意:这种情况是在如下的 arm-linux-gcc/g++ 编译器中出现:
[weikaifeng@weikaifeng test]$ arm-linux-gcc -v
……
gcc version 3.4.1
在Fedora14 系统自带的 GCC 编译器中,没有出现这种情况。
如下是一个测试的例子:
typedef unsigned char INT8U;
typedef unsigned long long INT64U;
struct _TEST
{
INT64U id;
};
typedef struct _TEST test;
void func(INT8U* buf)
{
int i = 0;
INT8U *p = NULL;
INT64U id = 0;
INT64U p_id = 0;
test *t = (test*)buf;
printf("t->id = %llu \n", t->id);
printf("buf = "); //显示传递进来的 buf[] 值
for(i = 0; i < 8; i++)
{
printf("%2x ", buf[i]);
}
printf("\n");
//计算 buf[] 存放的 id 数据
for(i = 7; i >= 0; i--)
{
id = id*256 + buf[i];
}
printf("id = %llu \n", id);
//显示 t->id 的内存数据
p = (INT8U*)&(t->id);
printf("p = ");
for(i = 0; i < 8; i++)
{
printf("%2x ", *p);
p++;
}
printf("\n");
printf("t->id = %llu \n", t->id);
//把 t->id 赋给一个变量,再次显示这个变量中 内存数据,发现与 t->id 的实际内存不一样
//而是 main(); 函数中定义的整个 buf[] 是一样的。
//所以,可以推论 使用 printf(); 输出 t->id 的时候,引导到了 buf[2] 的前 2 个数据
p_id = t->id;
printf("p_id = %llu \n", p_id);
p = (INT8U*)&p_id;
printf("p = ");
for(i = 0; i < 8; i++)
{
printf("%2x ", *p);
p++;
}
printf("\n");
}
int main(void)
{
int i = 0;
INT64U id = 8868;
INT8U buf[10];
buf[0] = 0x01;
buf[1] = 0x02;
for(i = 0; i < 8; i++)
{
buf[i + 2] = id % 256;
id = id / 256;
}
printf("buf = ");
for(i = 0; i < 10; i++)
{
printf("%2x ", buf[i]);
}
printf("\n");
func(&buf[2]); //注意,传的只是从 buf[2] 开始,为了测试在 func(); 函数中是否引用到 buf[2] 前面的 2 个字节
printf("\nhehe.....\n");
return 0;
}
在 Fedora14 系统自带的 GCC 编译环境中编译运行的结果如下:
[weikaifeng@weikaifeng test]$ ./test
buf = 1 2 a4 22 0 0 0 0 0 0
t->id = 8868
buf = a4 22 0 0 0 0 0 0
id = 8868
p = a4 22 0 0 0 0 0 0
t->id = 8868
p_id = 8868
p = a4 22 0 0 0 0 0 0
hehe.....
结果是完全正确的,如果使用 arm-linux-gcc v3.4.1 版本的编译器编译,然后,下载到ARM板上运行,得到的结果如下:
dig ~# ./arm_test
buf = 1 2 a4 22 0 0 0 0 0 0
t->id = 581173761
buf = a4 22 0 0 0 0 0 0
id = 8868
p = a4 22 0 0 0 0 0 0
t->id = 581173761
p_id = 581173761
p = 1 2 a4 22 0 0 0 0
hehe.....
可以看到,相同的一份代码,使用不同的编译器编译,得到不同的结果。同时,也可以推理出 arm-linux-gcc v3.4.1 版本的编译应该有这样的一个漏洞。对于 ARM 板上的芯片和当前PC上的CPU芯片,处理内存都是小端法,不会有影响。就应该是 arm-linux-gcc v3.4.1 版本编译器的问题。
最后,为了解决在ARM板上的应用程序能够显示正确的数据,可以利用:把 buf[ ] 缓存中的数据复制到一个相应的结构体中,然后,再显示结构体中的数据。
void show_card_info(INT8U *buf, INT16U count)
{
TGDR_Event event;
bzero(&event, sizeof(TGDR_Event));
for(int i = 0; i < count; i++)
{
buf = buf + i*sizeof(TGDR_Event);
memcpy(&event, buf, sizeof(TGDR_Event)); //把 buf[] 缓存中的数据复制到一个结构体中再操作
printf("*********** i = %d **********\n", i);
printf("CardNo = %llu \n", event.CardNo);
printf("EvtCode = %u \n", event.EvtCode);
printf("eDate = %u \n", event.eDate);
printf("eTime = %u \n", event.eTime);
printf("EvtType = %u \n", event.EvtType);
printf("EvtActType = %u \n", event.EvtActType);
printf("DotAddr = %u \n", event.DotAddr);
}
}
转载地址:https://mylinux.blog.csdn.net/article/details/8966525 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!