#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 代码在我的 PC 上编译并运行时会打印
0x1f00
。
但是当我将其刷新到嵌入式目标(uController)并进行调试时,我发现
(*X).Element1[0] = 0x001f
。
1- 为什么 PC 上和嵌入式目标上的结果不同?
2- 我可以在这段代码中修改什么,以便它在 PC 机壳中打印
0x001f
,
无需更改代码核心(通过添加编译器选项或其他内容)。
short
通常是两个字节和 16 位。当你说:
short s;
((char*)&s)[0] = 0x00;
((char*)&s)[1] = 0x1f;
这会将这两个字节中的第一个设置为
0x00
,将这两个字节中的第二个设置为 0x1f
。问题是 C++ 没有指定第一个或第二个字节的设置对整体 short
的值有何作用,因此不同的平台可以做不同的事情。特别是,一些平台表示设置第一个字节会影响 short
的 16 位中的“最高有效”位,设置第二个字节会影响 short
的 16 位中的“最低有效”位。其他平台则相反;设置第一个字节影响最低有效位,设置第二个字节影响最高有效位。这两种平台行为分别称为大端和小端。
获得独立于这些差异的一致行为的解决方案是不以这种方式访问
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;
}
但请记住,这种类型转换通常并不安全;你应该只将指针投射回原来的位置。
F2
的定义:
void F2(short * p)
{
*p = 0x1F;
}
void F1(CustomStruct* X)
{
F2(&X.Element1[0]);
printf("s = %x\n", (*X).Element1[0]);
}
当您将对象重新解释为字符数组时,您暴露了表示的
实现细节,这本质上是不可移植的并且......依赖于实现。
如果您需要进行 I/O,即与固定的、指定的外部线路格式的接口,请使用和
ntohs
等函数进行转换并将平台细节留给您的库。
没有一个很好的方法来修改 PC 上的 C 代码,除非您将
char *
引用替换为
short *
引用,并且也许使用宏来抽象微控制器和 PC 之间的差异。例如,您可以创建一个宏
PACK_BYTES(hi, lo)
,以相同的方式将两个字节打包成一个短字节,而不管机器字节序如何。 你的例子变成:
#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;
}