#include "stdio.h"
typedef struct CustomStruct
{
short Element1[10];
}CustomStruct;
void F2(char* Y)
{
*Y=0x00;
Y++;
*Y=0x1F;
}
void F1(CustomStruct* X)
{
F2((char *)X);
printf("s = %x\n", (*X).Element1[0]);
}
int main(void)
{
CustomStruct s;
F1(&s);
return 0;
}
上面的C代码在编译并在我的电脑上运行时打印0x1f00
。
但是当我将它闪存到嵌入式目标(uController)并进行调试时,我发现了
(*X).Element1[0] = 0x001f
。
1-为什么PC和嵌入式目标上的结果有所不同?
2-我可以在此代码中修改哪些内容,以便在PC机箱中打印0x001f
,
不改变代码核心(通过添加编译器选项或其他东西)。
答案 0 :(得分:3)
short
通常是两个字节和16位。当你说:
short s;
((char*)&s)[0] = 0x00;
((char*)&s)[1] = 0x1f;
这将这两个字节中的第一个设置为0x00
,将这两个字节中的第二个设置为0x1f
。问题是C ++没有指定第一个或第二个字节对整个short
的值的设置,因此不同的平台可以做不同的事情。特别是,有些平台认为设置第一个字节会影响short
16位的“最高有效”位,而设置第二个字节会影响short
的'最低有效'位。 16位。其他平台则相反;设置第一个字节会影响最低有效位,设置第二个字节会影响最高有效位。这两种平台行为分别称为big-endian和little-endian。
获得与这些差异无关的一致行为的解决方案是不以这种方式访问short
的字节。相反,您应该使用语言 定义的方法来操纵short
的值,例如使用按位和算术运算符。
short s;
s = (0x1f << 8) | (0x00 << 0); // set the most significant bits to 0x1f and the least significant bits to 0x00.
问题是,由于种种原因,我只能更改F2功能的主体。我不能改变它的原型。有没有办法在它被铸造之前找到Y的尺寸?
仅使用char*
无法确定原始类型和尺寸。您必须通过其他方式了解正确的类型和大小。如果除了CustomStruct之外从未调用F2
,那么您可以简单地将char*
转发回CustomStruct
,如下所示:
void F2(char* Y)
{
CustomStruct *X = (CustomStruct*)Y;
X->Element[0] = 0x1F00;
}
但请记住,这样的演员阵容一般不安全;你应该只将指针强制转换回最初投射的内容。
答案 1 :(得分:2)
便携式方法是更改F2
:
void F2(short * p)
{
*p = 0x1F;
}
void F1(CustomStruct* X)
{
F2(&X.Element1[0]);
printf("s = %x\n", (*X).Element1[0]);
}
当您将对象重新解释为字符数组时,您将公开表示的实现细节,这本身就是非可移植的并且依赖于实现。
如果您需要进行I / O操作,即使用固定的,指定的外部有线格式进行接口,请使用htons
and ntohs
之类的函数进行转换,并将平台细节保留在库中。
答案 2 :(得分:1)
看起来PC是小端,目标是big-endian,或者是16位char。
在PC上修改C代码没有很好的方法,除非用char *
引用替换short *
引用,并且可能使用宏来抽象微控制器和你的微控制器之间的差异PC。
例如,您可以创建一个宏PACK_BYTES(hi, lo)
,它以相同的方式将两个字节打包成一个short,而不管机器端序。你的例子变成了:
#include "stdio.h"
#define PACK_BYTES(hi,lo) (((short)((hi) & 0xFF)) << 8 | (0xFF & (lo)))
typedef struct CustomStruct
{
short Element1[10];
}CustomStruct;
void F2(short* Y)
{
*Y = PACK_BYTES(0x00, 0x1F);
}
void F1(CustomStruct* X)
{
F2(&(X->Element1[0]));
printf("s = %x\n", (*X).Element1[0]);
}
int main(void)
{
CustomStruct s;
F1(&s);
return 0;
}