Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't there an endianness modifier in C++ like there is for signedness?

(I guess this question could apply to many typed languages, but I chose to use C++ as an example.)

Why is there no way to just write:

struct foo {     little int x;   // little-endian     big long int y; // big-endian     short z;        // native endianness }; 

to specify the endianness for specific members, variables and parameters?

Comparison to signedness

I understand that the type of a variable not only determines how many bytes are used to store a value but also how those bytes are interpreted when performing computations.

For example, these two declarations each allocate one byte, and for both bytes, every possible 8-bit sequence is a valid value:

signed char s; unsigned char u; 

but the same binary sequence might be interpreted differently, e.g. 11111111 would mean -1 when assigned to s but 255 when assigned to u. When signed and unsigned variables are involved in the same computation, the compiler (mostly) takes care of proper conversions.

In my understanding, endianness is just a variation of the same principle: a different interpretation of a binary pattern based on compile-time information about the memory in which it will be stored.

It seems obvious to have that feature in a typed language that allows low-level programming. However, this is not a part of C, C++ or any other language I know, and I did not find any discussion about this online.

Update

I'll try to summarize some takeaways from the many comments that I got in the first hour after asking:

  1. signedness is strictly binary (either signed or unsigned) and will always be, in contrast to endianness, which also has two well-known variants (big and little), but also lesser-known variants such as mixed/middle endian. New variants might be invented in the future.
  2. endianness matters when accessing multiple-byte values byte-wise. There are many aspects beyond just endianness that affect the memory layout of multi-byte structures, so this kind of access is mostly discouraged.
  3. C++ aims to target an abstract machine and minimize the number of assumptions about the implementation. This abstract machine does not have any endianness.

Also, now I realize that signedness and endianness are not a perfect analogy, because:

  • endianness only defines how something is represented as a binary sequence, but now what can be represented. Both big int and little int would have the exact same value range.
  • signedness defines how bits and actual values map to each other, but also affects what can be represented, e.g. -3 can't be represented by an unsigned char and (assuming that char has 8 bits) 130 can't be represented by a signed char.

So that changing the endianness of some variables would never change the behavior of the program (except for byte-wise access), whereas a change of signedness usually would.

like image 441
Lena Schimmel Avatar asked Nov 28 '17 12:11

Lena Schimmel


People also ask

Is C language little endian?

If machine is little endian then *c will be 1 (because last byte is stored first) and if the machine is big endian then *c will be 0. Does endianness matter for programmers?

What determines the endianness?

Broadly speaking, the endianness in use is determined by the CPU. Because there are a number of options, it is unsurprising that different semiconductor vendors have chosen different endianness for their CPUs.

Do bytes have endianness in C?

Since you can't normally address the bits within a byte individually, there's no concept of "bit endianness" generally.

Does endianness matter for a single byte?

Again, endian-ness does not matter if you have a single byte. If you have one byte, it's the only data you read so there's only one way to interpret it (again, because computers agree on what a byte is).


1 Answers

What the standard says

[intro.abstract]/1:

The semantic descriptions in this document define a parameterized nondeterministic abstract machine. This document places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.

C++ could not define an endianness qualifier since it has no concept of endianness.

Discussion

About the difference between signness and endianness, OP wrote

In my understanding, endianness is just a variation of the same principle [(signness)]: a different interpretation of a binary pattern based on compile-time information about the memory in which it will be stored.

I'd argue signness both have a semantic and a representative aspect1. What [intro.abstract]/1 implies is that C++ only care about semantic, and never addresses the way a signed number should be represented in memory2. Actually, "sign bit" only appears once in the C++ specs and refer to an implementation-defined value.
On the other hand, endianness only have a representative aspect: endianness conveys no meaning.

With C++20, std::endian appears. It is still implementation-defined, but let us test the endian of the host without depending on old tricks based on undefined behaviour.


1) Semantic aspect: an signed integer can represent values below zero; representative aspect: one need to, for example, reserve a bit to convey the positive/negative sign.
2) In the same vein, C++ never describe how a floating point number should be represented, IEEE-754 is often used, but this is a choice made by the implementation, in any case enforced by the standard: [basic.fundamental]/8 "The value representation of floating-point types is implementation-defined".

like image 129
YSC Avatar answered Oct 07 '22 11:10

YSC