C ++ 14中二进制文字的字节顺序是什么?

问题描述 投票:42回答:7

我试过四处搜索,但一直没能找到关于二进制文字和字节序的东西。二进制文字是little-endian,big-endian还是其他什么东西(比如匹配目标平台)?

举个例子,0b0111的十进制值是多少?是7吗?平台具体?别的什么?编辑:我选择了一个错误的值7,因为它表示在一个字节内。尽管如此,这个问题仍得到了充分的回答。

一些背景:基本上我试图找出最低有效位的值是什么,并用二进制文字掩盖它似乎是一个很好的方法...但只有在有一些关于字节序的保证。

c++ endianness c++14
7个回答
71
投票

简短的回答:没有一个。用你在纸上书写的方式写出数字。

答案很长:除非您真的试图将其结束(例如使用指针技巧),否则Endianness永远不会直接暴露在代码中。 0b0111是7,它与十六进制,写作规则相同

int i = 0xAA77;

并不意味着0x77AA在某些平台上,因为这是荒谬的。 32位整数中缺少的额外0会在哪里?他们会在前面填充,然后整个东西翻到0x77AA0000,或者他们会在之后添加吗?如果是这样的话,我不知道会有人期待什么。

关键是C ++不对机器的字节序做出任何假设*,如果使用基元和它提供的文字编写代码,机器之间的行为将是相同的(除非你开始绕过类型系统,您可能需要这样做)。

要解决您的更新:数字将是您写出来的方式。这些位不会被重新排序或任何这样的事情,最重要的位在左侧,最低位在右侧。


这里似乎存在关于字节序的误解。字节顺序指的是字节在内存中的排序方式以及它们必须如何解释。如果我给你的号码为“4172”并说“如果这是四千七百二十二,那么会有什么样的结尾”你无法给出答案,因为这个问题没有意义。 (有人认为左边最大的数字意味着大端,但没有内存地址,字节序的问题是不负责任的或相关的)。这只是一个数字,没有要解释的字节,没有内存地址。假设4字节整数表示,与之对应的字节为:

        low address ----> high address
Big endian:    00 00 10 4c
Little endian: 4c 10 00 00

因此,给出其中任何一个并告诉“这是计算机4172的内部表示”,你可以确定它的小端还是大端。

所以现在考虑你的二进制文字0b0111这4位代表一个nybble,并且可以存储为

              low ---> high
Big endian:    00 00 00 07
Little endian: 07 00 00 00

但你不必关心,因为这也是由硬件处理的,语言规定编译器从左到右读取,最重要的位到最不重要的位

字节序不是关于个别位。鉴于一个字节是8位,如果我递给你0b00000111并说“这是小或大端?”再次你不能说因为你只有一个字节(没有地址)。字节顺序与字节中的位顺序无关,它指的是整个字节相对于地址的顺序(除非你有一位字节)。

您无需关心计算机在内部使用的内容。 0b0111只是节省了你不必写东西的时间

unsigned int mask = 7 // only keep the lowest 3 bits

通过写作

unsigned int mask = 0b0111;

无需评论解释数字的重要性。


*在c ++ 20中,您可以使用std::endian检查字节序。


40
投票

所有整数文字(包括二进制文字)的解释方式与我们通常读取的数字相同(最左边的数字最重要)。

C ++标准保证对文字的相同解释,而不必关心您所处的特定环境。因此,在这种情况下,您不必关心字节序。

你的0b0111的例子总是等于七。

C ++标准在数字文字方面没有使用字节顺序。相反,它只是简单地描述了文字具有一致的解释,并且解释是您期望的解释。

C ++标准 - 整数文字 - 2.14.2 - 第1段

整数文字是一个没有句点或指数部分的数字序列,可选地分隔单引号,在确定其值时将被忽略。整数文字可以具有指定其基数的前缀和指定其类型的后缀。数字序列的词汇第一个数字是最重要的。二进制整数文字(基数为2)以0b或0B开头,由一系列二进制数字组成。八进制整数文字(基数为8)以数字0开头,由一系列八进制数字组成。十进制整数文字(十进制)以0以外的数字开头,由一系列十进制数字组成。十六进制整数文字(基数为16)以0x或0X开头,由十六进制数字序列组成,包括十进制数字和字母a到f和A到F,十进制值为十到十五。 [例子:12号可以写成12,014,0XC或0b1100。文字1048576,1'048'576,0X100000,0x10'0000和0'004'000'000都具有相同的值。 - 结束例子]

Wikipedia describes what endianness is, and uses our number system as an example to understand big-endian.

术语字节序和字节序是指当这些字节存储在计算机存储器中时用于解释构成数据字的字节的约定。

Big-endian系统将字的最高有效字节存储在最小地址中,最低有效字节存储在最大地址中(也见最高有效位)。相反,小端系统将最低有效字节存储在最小地址中。

关于字节序的一个例子是考虑如何以位值表示法写入和读取十进制数。假设编写系统从左到右写入数字,最左边的位置类似于所使用的最小内存地址,最右边的位置是最大的。例如,第一百二十三写为1 2 3,最左边有数百个。读取此数字的任何人都知道最左边的数字具有最大的位置值。这是日常生活中遵循的大端会议的一个例子。

在这种情况下,我们将整数文字的数字视为“单词的字节”,并将该字视为文字本身。此外,文字中最左侧的字符被认为具有最小的地址。

使用文字1234,数字一,二,三和四是“一个字的字节”,而1234是“字”。使用二进制文字0b0111,数字零,一,一和一是“单词的字节”,单词是0111

这种考虑使我们能够理解C ++语言环境中的字节序,并表明整数文字类似于“big-endian”。


10
投票

您错过了源代码中编写的字节序和目标代码中表示的字节序之间的区别。每个答案都不足为奇:源代码文字是bigendian,因为这是人类阅读它们的方式,在目标代码中它们被编写但是目标读取它们。

由于字节根据定义是存储器访问的最小单位,因此我认为甚至不能将字节顺序归结为字节中任何内部位的表示 - 这是发现更大数字的字节顺序的唯一方法(无论是有意还是令人惊讶的是通过分段从存储中访问它们,并且字节根据定义是最小的可访问存储单元。


7
投票

C / C ++语言不关心多字节整数的字节顺序。 C / C ++编译器可以。编译器会解析您的源代码并为特定目标平台生成机器代码。通常,编译器以与存储整数相同的方式存储整数文字;这样目标CPU的指令将直接支持在内存中读取和写入它们。

编译器会处理目标平台之间的差异,因此您不必这样做。

您需要担心字节顺序的唯一时间是与其他具有不同字节顺序的系统共享二进制值。然后您将逐字节读取二进制数据,并按正确顺序排列内存中的字节。您的代码正在运行的系统。


3
投票

一张照片有时超过千字。

source vs. memory endianness


0
投票

Endianness是实现定义的。该标准保证每个对象都有一个对象表示形式为charunsigned char的数组,您可以通过调用memcpy()memcmp()来处理它。在C ++ 17中,reinterpret_cast指向或指向任何对象类型(不是指向void的指针,指向函数的指针或nullptr)指向charunsigned charstd::byte的指针是合法的,它们是有效的别名任何对象类型。

当人们谈论“字节序”时,人们的意思是该对象表示中的字节顺序。例如,如果你声明unsigned char int_bytes[sizeof(int)] = {1};int i;然后memcpy( &i, int_bytes, sizeof(i));你得到0x01,0x01000000,0x0100,0x0100000000000000,还是别的什么?答案是:是的。有实际的实现可以产生这些结果,并且它们都符合标准。这样做的原因是编译器可以使用CPU的本机格式。

当程序需要通过Internet发送或接收数据时,这通常会出现这种情况,其中所有标准都定义数据应该以big-endian顺序传输,在像x86这样的小端CPU上。因此,一些网络库指定特定参数和结构字段是否应以主机或网络字节顺序存储。

这种语言可以让你通过随意地对象对象的位来对自己进行拍摄,但它可能会为你提供一个陷阱表示,如果你以后尝试使用它会导致未定义的行为。 (这可能意味着,例如,重写一个虚函数表以注入任意代码。)<type_traits>头有几个模板来测试用对象表示做事是否安全。如果类型为memcpy( &dest, &src, sizeof(dest) ),您可以使用is_trivially_copyable将一个对象复制到另一个相同类型的对象上。如果它是is_trivially_move_constructible,你可以复制到正确对齐的未初始化的内存。您可以测试两个相同类型的对象是否与memcmp( &a, &b, sizeof(a) )相同,并且如果类型为has_unique_object_representations,则通过对其对象表示中的字节应用散列函数来正确地散列对象。整数类型没有陷阱表示,依此类推。但是,在大多数情况下,如果您正在对字节序很重要的对象表示进行操作,那么您告诉编译器假设您知道您在做什么,而您的代码将无法移植。

正如其他人所提到的,二进制文字首先用最高位数写成,如十进制,八进制或十六进制文字。这与endianness不同,不会影响您是否需要从Internet读取的TCP头中调用端口号上的ntohs()


-6
投票

您可能希望将C或C ++或任何其他语言视为本质上的小端(考虑按位运算符的工作原理)。如果底层硬件是大端,编译器确保数据存储在大端(对于其他字节序也是如此),但是你的位操作就好像数据是小端的一样。要记住的是,就语言而言,数据是小端的。当您将数据从一种类型转换为另一种类型时,会出现与字节顺序相关的问题。只要你不这样做,你就是好人。

我被问及“C / C ++语言本质上是小端”的说法,因此我提供了一个例子,许多人都知道它是如何工作的但是我在这里。

typedef union
{
    struct {
        int a:1;
        int reserved:31;
    } bits;

    unsigned int value;
} u;

u test;
test.bits.a = 1;
test.bits.reserved = 0;

printf("After bits assignment, test.value = 0x%08X\n", test.value);

test.value = 0x00000001;

printf("After value assignment, test.value = 0x%08X\n", test.value);

小端系统的输出:

After bits assignment, test.value = 0x00000001
After value assignment, test.value = 0x00000001

大端系统的输出:

After bits assignment, test.value = 0x80000000
After value assignment, test.value = 0x00000001

那么,如果你不知道处理器的字节序,那么一切都在哪里出来?在小端系统!因此,我说C / C ++语言本质上是小端。

© www.soinside.com 2019 - 2024. All rights reserved.