我对系统/ cpu /程序的字节顺序感到困惑 所以我必须提出一些问题才能让我明白。
如果我只在我的C ++程序中使用类型char
:
void main()
{
char c = 'A';
char* s = "XYZ";
}
然后将此程序编译为名为a.out
的可执行二进制文件
a.out
可以在little-endian和big-endian系统上运行吗?
如果我的Windows XP系统是little-endian,我可以在VMWare / VirtualBox中安装大端Linux系统吗? 什么使系统成为小端或大端?
如果我想编写一个与字节顺序无关的C ++程序,我需要考虑什么?
答案 0 :(得分:20)
a.out可以在little-endian和big-endian系统上运行吗?
不,因为几乎任何两个具有不同字节序的CPU都不会运行相同的指令集。 C ++不是Java;你没有编译成被编译或解释的东西。您编译为特定CPU的程序集。 endian-ness是CPU的一部分。
但这不是endian问题。您可以为不同的CPU编译该程序,这些可执行文件可以在各自的CPU上正常工作。
什么使系统成为小端或大端?
就C或C ++而言,CPU。计算机中的不同处理单元实际上可以有不同的端序(GPU可以是大端,而CPU是小端),但这有点不常见。
如果我想编写一个字节顺序独立的C ++程序,我需要考虑什么?
只要您遵守C或C ++规则,就不必关心字节序问题。
当然,您也无法将文件直接加载到POD结构中。或者读取一系列字节,假装它是一系列无符号短路,然后将其作为UTF-16编码的字符串处理。所有这些都进入了实现定义行为的领域。
“未定义”和“实现定义”行为之间存在差异。当C和C ++规范说某些东西是“未定义的”时,它基本上意味着所有破碎都可以随之发生。如果你继续这样做(并且你的程序没有崩溃),你可能会得到不一致的结果。当它表示实现定义了某些内容时,您将获得该实现的一致结果。
如果在VC2010中为x86编译,那么假装一个字节数组是无符号短数组(即:unsigned char *byteArray = ...; unsigned short *usArray = (unsigned short*)byteArray
)时会发生什么。在编译big-endian CPU时,你会得到与编译little-endian CPU时不同的答案。
通常,endian问题是可以本地化为输入/输出系统的问题。网络,文件阅读等。应该在代码库的极端处理它们。
答案 1 :(得分:8)
问题1:
a.out可以在little-endian和big-endian系统上运行吗?
没有。因为a.out
已针对其定位的任何体系结构进行了编译。它不会在与其不兼容的另一个架构上运行。
但是,该简单程序的源代码没有任何可能在不同的端机器上中断的内容。
所以是的(来源)将正常工作。 (嗯......除void main()
之外,您应该使用int main()
代替
问题2:
如果我的WindowsXP系统是little-endian,我可以安装一个big-endian VMWare / VirtualBox中的Linux系统?
Endian-ness由硬件决定,而不是OS。因此,无论您在其上安装什么(本机)VM,它都将与主机相同。 (因为x86都是小端)
什么使系统成为小端或大端?
以下是一些关于小端与大端的行为不同的例子:
uint64_t a = 0x0123456789abcdefull;
uint32_t b = *(uint32_t*)&a;
printf("b is %x",b)
*请注意,这违反了严格别名,仅用于演示目的。
Little Endian : b is 89abcdef
Big Endian : b is 1234567
在little-endian上,a
的低位存储在最低地址。因此,当您以{32}整数访问a
时,您将读取它的低32位。在big-endian上,你将读取高32位。
问题3:
如果我想编写一个字节顺序独立的C ++程序,我该怎么做 需要考虑到吗?
只需遵循标准的C ++规则,就像我上面展示的示例一样,不要做任何丑陋的事情。避免未定义的行为,避免类型惩罚......
答案 2 :(得分:3)
Little-endian / big-endian是硬件的属性。通常,为一个硬件编译的二进制代码不能在另一个硬件上运行,除非在解释机器代码的虚拟化环境中,并为其模拟目标硬件。有双端CPU(例如ARM,IA-64)具有改变字节顺序的开关。
就字节顺序无关的编程而言,唯一需要做的就是处理网络问题。有ntohl
and htonl
等函数可以帮助您将硬件的字节顺序转换为网络的字节顺序。
答案 3 :(得分:2)
首先要说明的是,endianness是硬件属性,而不是软件/操作系统属性,因此WinXP和Linux不是big-endian或little endian,而是它们运行的硬件是big-endian或者小端。
Endianness是对数据类型中存储字节的顺序的描述。 big-endian系统首先存储最重要(读取最大值)值,而little-endian系统首先存储最低有效字节。并非强制要求每个数据类型与系统上的其他数据类型相同,因此您可以使用混合端系统。
一个小端的程序不会在大端系统上运行,但是对于可用的指令集而言,它比编译它的系统的字节序更多。
如果要编写独立于字节顺序的程序,则只需要不依赖于数据的字节顺序。
答案 4 :(得分:2)
1:编译器的输出取决于您提供的选项以及是否使用交叉编译器。默认情况下,它应该在您正在编译它的操作系统上运行,而不是在其他操作系统上运行(可能不是其他相同类型的操作系统;例如,并非所有Linux二进制文件都在所有Linux安装上运行)。在大型项目中,这将是您最不关心的问题,因为库等需要在每个系统上进行不同的构建和链接。使用正确的构建系统(如make)将处理大部分内容,而无需担心。
2:虚拟机以这样一种方式抽象硬件,即允许任何东西在其他任何东西中运行。只要操作系统在相同的硬件上运行并支持正在使用的虚拟化模型,操作系统如何管理内存就不重要了。字节顺序表示字节顺序;如果是左右或左右(或其他一些格式)。一些硬件支持两者兼容,虚拟化允许两者在这种情况下共存(尽管我不知道这有什么用,除了它在理论上是可能的)。但是,Linux适用于许多不同的体系结构(以及除Ixxx以外的Windows),因此情况更复杂。
3:如果你使用原始内存,例如使用二元运算符,你可能会让自己处于依赖于字节序的位置。但是,大多数现代编程都处于比这更高的水平。因此,您可能会注意到,如果您遇到可能会产生基于字节序限制的内容。如果需要这样,您可以使用预处理器始终为两个字节序实现选项。
答案 5 :(得分:1)
系统的 endianness 确定如何解释字节,因此将哪个位视为“第一个”,将哪个位视为“最后一个”。
只有在从程序外部的某些来源(如磁盘或网络)加载或保存时,您才需要关心它。