指针投射字节序

Pointers Casting Endianness

本文关键字:字节 指针      更新时间:2023-10-16
#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 = %xn", (*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 = %xn", (*X).Element1[0]);
}

当您将对象重新解释为字符数组时,您将公开表示的实现细节,这本质上是不可移植的,并且依赖于实现

如果您需要执行 I/O,即使用固定的、指定的外部线路格式进行接口,请使用 htonsntohs 等功能进行转换,并将平台细节留给您的库。

看起来PC

是小端序,目标要么是大端序,要么是16位字符。

没有

一种方法可以修改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 = %xn", (*X).Element1[0]);
}
int main(void)
{
  CustomStruct s;
  F1(&s);
  return 0;
}