小端序和大端序

8

假设我有一个4字节的整数,我想将其转换为2字节的短整数。在小端和大端中,这个短整数将由这个4字节整数的两个最低有效字节组成,这样理解正确吗?

第二个问题:
在小端和大端处理器中,这段代码的结果会是什么?

int i = some_number;  
short s = *(short*)&i;

在我看来,在大端处理器中,将复制两个最高有效字节,在小端处理器中,将复制两个最低有效字节。


我建议在复制之前使用数学方法将数字缩小到适当的范围(大小)。编译器会维护字节序,因此您不必担心太多。复制变量的部分会导致字节序问题,正如您所提出的那样。 - Thomas Matthews
5个回答

12

我是否正确,短整型将由这个4字节整数的2个最低有效字节组成?

是的,根据定义。

bigE和littleE的区别在于最低有效字节是否在最低地址。在little endian处理器中,最低地址是最不重要的位,x86就是这样做的。

在little E上,它们会得到相同的结果。

short s = (short)i;
short s = *(short*)&i;

在大端处理器上,最高地址是最不重要的位,例如68000和Power PC采用这种方式(实际上,Power PC可以是两种类型,但苹果的PPC机器使用bigE)。

对于big E,它们给出相同的结果。

short s = (short)i;
short s = ((short*)&i)[1]; // (assuming i is 4 byte int)

正如你所看到的,小端字节序允许您获取操作数最低有效位,而无需知道它有多大。小端字节序对于保持向后兼容性具有优势。

那么大端字节序有什么优点呢?它创建的十六进制转储更易于阅读

实际上,摩托罗拉的工程师认为减轻读取十六进制转储的负担比向后兼容性更重要。英特尔的工程师则持相反观点。


@Josef:是的,我确信硬件设计师更喜欢小E有许多小原因,兼容性可能对他们来说并不那么重要。但事实证明,在从80886转移到286/386时,它确实非常重要。为8088编写的代码仍可在现代x86/x64处理器上运行。 - John Knoeller
是的,x86架构在二进制级别上是向后兼容的,这是设计上的(好坏参半),始终保留了先前一代的整个指令集。诚然,这超出了我的专业领域,但除了可能为mov指令稍微简化电路逻辑之外,小端序在这个领域有多大帮助呢?您仍然需要针对不同的数据大小(字节,字,双字等)使用不同的操作码。 - Josef Grahn
2
大端和小端的决策与向后兼容性关系不大。在所有处理器中,保持与先前版本相同的字节序有助于促进代码重用。在原始处理器上选择大端或小端更多地涉及人类可读性(大端)与简化电路(小端)。英特尔选择了小端,摩托罗拉选择了大端。许多当前处理器可以在运行时切换字节序。 - Thomas Matthews
@John Knoeller:“如果你想在32位处理器上使用bigE而不是littleE支持16位指令集,那么这将更加困难并需要更多的电路。” 你能说一下原因吗? - Lazer
2
@Lazer:我说为什么。在BigE上,除非您知道地址和大小,否则无法加载值的低16位。在LittleE上,您只需要知道地址。对于我们来说,BigE似乎更“自然”,因为我们赋予数字最左边的数字更多的意义。它们向左增长,而其他数据向右增长。BigE迎合了那一点点的不合理性,在复杂性方面付出了代价。LittleE则以满足硬件需求为代价,而不顾及人类。如果它在这方面不比BigE更好,那么它就不会存在。 - John Knoeller
显示剩余3条评论

2
  1. 是的。当你转换数值时,你不必担心字节序问题。

  2. 是的。当你转换指针时,你需要考虑字节序问题。


实际上,你只有在序列化数据(即文件或网络I/O)时才需要以这种方式转换指针。但在这种情况下,确实需要担心,因为读取器可能使用不同的字节顺序。 - Josef Grahn

1

你应该意识到你的第二个例子

int i = some_number;  
short s = *(short*)&i;

这不是有效的C代码,因为它违反了严格别名规则。在某些优化级别和/或编译器下,它很可能会失败。

使用联合体来解决这个问题:

union {
   int   i;
   short s;
} my_union;

my_union.i = some_number;
printf("%d\n",my_union.s);

另外,正如其他人所指出的那样,您不能假设您的整数将是4个字节。在需要特定大小时最好使用int32_t和int16_t。


它如何违反严格别名规则? - Roger Pate
这不是别名违规。它只是颠覆了类型系统,从未实际创建指针。 - John Knoeller

1

首先,您可能已经知道,但让我提一下,int 的大小不能保证为 4 个字节,short 的大小在所有平台上都是 2 个字节。

如果您的第一个问题意思是这样的:

int i = ...;
short s = (short)i;

是的,s 将包含 i 的低字节。

我认为对于你的第二个问题,答案也是肯定的;在字节级别上,系统的字节序确实会发挥作用。


0
如果你真的想把一个int转换成short,那么就直接这样做:
short int_to_short(int n) {
  if (n < SHRT_MIN) return SHRT_MIN;
  if (n > SHRT_MAX) return SHRT_MAX;
  return (short)n;
}

你甚至不必担心字节序问题,这门语言会为你处理好。如果你确定 n 在 short 类型的范围内,那么也可以跳过检查。


1
我并不担心,只是好奇结果会是什么。 - Tomek Tarczynski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接