Thread overview
Endianness - How to test code for portability
Mar 12, 2021
Preetpal
Mar 12, 2021
Dennis
Mar 12, 2021
Preetpal
Mar 13, 2021
Patrick Schluter
March 12, 2021
In the portability section of the language spec, they talk about endianness (https://dlang.org/spec/portability.html#endianness)  which refers "to the order in which multibyte types are stored." IMO if you wanted to actually be sure your code is portable across both big endian and little endian systems, you should actually run your code on both types of systems and test if there any issues.

The problem is that I am not aware of any big-endian systems that you can actually test on and if there is any D lang compiler support for any of these systems if they exist.

This is not an important issue to me but I was just curious to see if anyone actually tests for portability issues related to endianness by compiling their D Lang code for a big endian architecture and actually running it on that system.
March 12, 2021
On Friday, 12 March 2021 at 05:53:40 UTC, Preetpal wrote:
> This is not an important issue to me but I was just curious to see if anyone actually tests for portability issues related to endianness by compiling their D Lang code for a big endian architecture and actually running it on that system.

I have a png decoder, and I often avoid a dependency on endianness by using bit-shifts instead of casts. For example, this code reads a big-endian integer and returns a native-endian integer, regardless of architecture:

```
uint readUintBe(in ubyte[] s) {
    return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
}
```

There is a part in the decompression where a ubyte[] is cast to a uint[] for performance, and it assumes a little-endian byte order. There is a fallback for big-endian architectures, but also for CTFE, where reinterpretation through overlapped fields or array casts is not allowed. So the code is structured like this:

```
version(BigEndian) {
    private enum bigEndian = true;
} else {
    private enum bigEndian = false;
}

int parse(in ubyte[] data) {
    if (__ctfe || bigEndian) {
        // Portable code
    } else {
        // Little-endian optimized code
    }
}
```

Then you can test both at runtime and compile time:
```
unittest {
    ubyte[] testData = [...];
    assert(parse(testData) == 3);
    static assert(parse(testData) == 3);
}
```

So no, I don't have a big-endian computer I can test it on, but I do test with CTFE, so I'm pretty sure I'm not relying on a specific byte order.
March 12, 2021
On Friday, 12 March 2021 at 10:26:55 UTC, Dennis wrote:
> ```
> version(BigEndian) {
>     private enum bigEndian = true;
> } else {
>     private enum bigEndian = false;
> }
>
> int parse(in ubyte[] data) {
>     if (__ctfe || bigEndian) {
>         // Portable code
>     } else {
>         // Little-endian optimized code
>     }
> }
> ```
>
> Then you can test both at runtime and compile time:
> ```
> unittest {
>     ubyte[] testData = [...];
>     assert(parse(testData) == 3);
>     static assert(parse(testData) == 3);
> }
> ```
>
> So no, I don't have a big-endian computer I can test it on, but I do test with CTFE, so I'm pretty sure I'm not relying on a specific byte order.

I never even thought of using CTFE for this purpose. Using CTFE to test cases you cannot simulate using runtime testing is a really great idea.
March 13, 2021
On Friday, 12 March 2021 at 05:53:40 UTC, Preetpal wrote:
> In the portability section of the language spec, they talk about endianness (https://dlang.org/spec/portability.html#endianness)  which refers "to the order in which multibyte types are stored." IMO if you wanted to actually be sure your code is portable across both big endian and little endian systems, you should actually run your code on both types of systems and test if there any issues.
>
> The problem is that I am not aware of any big-endian systems that you can actually test on and if there is any D lang compiler support for any of these systems if they exist.
>
> This is not an important issue to me but I was just curious to see if anyone actually tests for portability issues related to endianness by compiling their D Lang code for a big endian architecture and actually running it on that system.

Actual big endian systems? Not many around anymore:
- SPARC almost dead
- IBM z/system still around and not going away but a D implementation not very likely as it adds the other difficulty that it is not ASCII but EBCDIC.
- AVR32 doesn't look very vivid.
- Freescale Coldfire (as successor of 68K) also on a descending path
- OpenRISC superseded by RISC-V

Some CPU can do both but are generally used in little endian mode (ARM, Power) or also obsolete (Alpha, IA64).

While from an intellectual perspective endiannes support is a good thing, from a pure pragmatic vue it is a solved issue. Little endian won, definitely (except on the network in the TCP/IP headers).