# Endian in C++20 vs Julia; and byteswap in C++23

**URL:** <https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858>\
**Category:** Offtopic\
**Created:** [August 31, 2024, 4:41pm UTC](https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858 "2024-08-31T16:41:14Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [August 31, 2024, 4:41pm UTC](https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858/1 "2024-08-31T16:41:14Z")

</div>

If you never use `reinterpret`, directly (or indirectly), I think this is a non-issue in Julia, but otherwise it could affect correctness of possibly of all Julia programs.

I wish we could simply assume little endian (we can onl x86, and Arm we support), and I think we can mostly, with PowerPC I think the major big endian exception. So this is very much trivia for most users (note also `network order`, not a problem, just need to know of and do correctly).

[https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0463r1.html](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0463r1.html)

Does Julia have similar to check endianness? It’s advanced to use `reinterpret` and I can mostly think of it done on floating-point numbers to view then as integers, to access components. Julia probably has portable code to do such, are there other major uses of reinterpret?

Does Julia have similar to:  
[https://en.cppreference.com/w/cpp/numeric/byteswap](https://en.cppreference.com/w/cpp/numeric/byteswap)

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [August 31, 2024, 5:01pm UTC](https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858/2 "2024-08-31T17:01:18Z")

</div>

There are a bunch of endianness related functions here: [I/O and Network · The Julia Language](https://docs.julialang.org/en/v1/base/io-network/#Network-I/O)

I’ve used one of them once but that was years ago. Don’t know if this helps but thought it might be worth pointing out in case you haven’t seen them.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [August 31, 2024, 5:34pm UTC](https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858/3 "2024-08-31T17:34:20Z")

</div>

For what is worth Julia currently basically only runs on little endian systems. Making it work on big endian is perhaps possible, but in practice it’d require someone spending lots of time chasing all hardcoded assumptions of the endianness.

> [@Palli](#):
>
> PowerPC I think the major big endian exception.

Julia only runs on powerpc64le, which is the 64-bit little endian PowerPC architecture.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 31, 2024, 8:24pm UTC](https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858/4 "2024-08-31T20:24:00Z")

</div>

> [@Palli](#):
>
> Does Julia have similar to:  
> [https://en.cppreference.com/w/cpp/numeric/byteswap](https://en.cppreference.com/w/cpp/numeric/byteswap)

Yes, it has [`bswap`](https://docs.julialang.org/en/v1/base/numbers/#Base.bswap). Along with [`ltoh`](https://docs.julialang.org/en/v1/base/io-network/#Base.ltoh) and [`htol`](https://docs.julialang.org/en/v1/base/io-network/#Base.htol) etc. to convert the host’s native byte order to/from little-endian, and [`ENDIAN_BOM`](https://docs.julialang.org/en/v1/base/io-network/#Base.ENDIAN_BOM) to explicitly check the endianness.

So yes, Julia already has all the facilities you need to write code that works on any endianness.

As @giordano points out, however, since Julia currently only runs on little-endian systems there is probably lots of Julia code that implicitly assumes little-endianness that would have to be fixed if you were ever to port Julia to a big-endian system.

Right now it’s hard to foresee Julia being ported to any big-endian architecture, since little-endian is so dominant.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [September 2, 2024, 3:48pm UTC](https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858/5 "2024-09-02T15:48:23Z")

</div>

> [@stevengj](#):
>
> there is probably lots of Julia code that implicitly assumes little-endianness that would have to be fixed if you were ever to port Julia to a big-endian system.

Right, and probably in C++ too! I just noticed the trivia about C++ supporting big-endian better in C++20, so thought of what Julia does, and since it’s not important at all (on any non-legacy hardware), why introduce it then in C++20? I can only think of legacy like SPARC64 supporting big-endian only, and it actually has tier 1 support in Zig. Plus IBM s390x mainframe the only big-endian that I can think of living for a bit longer.

Could/should Julia support big-endian, at best as second-class? I mean could it implicitly do `htol` when reinterpreting, i.e. a no-op on little-endian, and no longer zero-cost, but cheap `bswap` then on big-endian?

Most upcoming languages, e.g. Rust have only tier 1 support for little endian.

MIPS was big-endian, but the Chinese offshoot:

> - All LoongArch systems are little-endian.
> - LoongArch is not binary compatible with either MIPS or RISC-V, although the ISA and ABI show heavy influence of the two.

Rust has in tier 2:

| [`loongarch64-unknown-linux-gnu`](https://doc.rust-lang.org/nightly/rustc/platform-support/loongarch-linux.html) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) |
| --- | --- |
| [`loongarch64-unknown-linux-musl`](https://doc.rust-lang.org/nightly/rustc/platform-support/loongarch-linux.html) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) |
| `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) |
| `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) |
| `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) |
| [`riscv64gc-unknown-linux-gnu`](https://doc.rust-lang.org/nightly/rustc/platform-support/riscv64gc-unknown-linux-gnu.html) | RISC-V Linux (kernel 4.20, glibc 2.29) |
| [`riscv64gc-unknown-linux-musl`](https://doc.rust-lang.org/nightly/rustc/platform-support/riscv64gc-unknown-linux-musl.html) | RISC-V Linux (kernel 4.20, musl 1.2.3) |
| `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17) |

…  
|[`aarch64-unknown-linux-ohos`](https://doc.rust-lang.org/nightly/rustc/platform-support/openharmony.html)|✓|ARM64 OpenHarmony|

and in tier 3:

|[`aarch64-nintendo-switch-freestanding`](https://doc.rust-lang.org/nightly/rustc/platform-support/aarch64-nintendo-switch-freestanding.html)|\*||ARM64 Nintendo Switch, Horizon|  
|[`aarch64-unknown-teeos`](https://doc.rust-lang.org/nightly/rustc/platform-support/aarch64-unknown-teeos.html)|?||ARM64 TEEOS|  
…  
|`aarch64_be-unknown-linux-gnu`|✓|✓|ARM64 Linux (big-endian)|

…

|[`armeb-unknown-linux-gnueabi`](https://doc.rust-lang.org/nightly/rustc/platform-support/armeb-unknown-linux-gnueabi.html)|✓|?|Arm BE8 the default Arm big-endian architecture since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).|

|[`i686-unknown-hurd-gnu`](https://doc.rust-lang.org/nightly/rustc/platform-support/hurd.html)|✓|✓|32-bit GNU/Hurd [1](https://doc.rust-lang.org/nightly/rustc/platform-support.html#x86_32-floats-return-ABI)|  
…  
|[`i686-unknown-redox`](https://doc.rust-lang.org/nightly/rustc/platform-support/redox.html)|✓||i686 Redox OS|

I’m more interested in supporting potentially interesting operating systems (and maybe older game hardware).

To answer my own question, in Julia to test/confirm you run on little-endian machine you would do:

if ENDIAN\_BOM == 0x04030201

but I’m thinking, to explicitly not have to do that, or use `htol` which does similar implicitly, could code be made just work?

```julia
ENDIAN_BOM

```

> The 32-bit byte-order-mark indicates the native byte order of the host machine. Little-endian machines will contain the value `0x04030201`. Big-endian machines will contain the value `0x01020304`.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 2, 2024, 3:57pm UTC](https://discourse.julialang.org/t/endian-in-c-20-vs-julia-and-byteswap-in-c-23/118858/6 "2024-09-02T15:57:58Z")

</div>

> [@Palli](#):
>
> to explicitly not have to do that, or use `htol` which does similar implicitly, could code be made just work?

You should rarely _need_ to check `ENDIAN_BOM` explicitly.

A common situation in which you might care about endian-ness is for binary I/O — you (or the spec) decide whether you want the format to be little-endian or big-endian, and use `htol` or `hton` when writing, respectively, and `ltoh` or `ntoh` when reading.

Better yet, use a portable binary format like HDF5.jl that already takes care of endian-ness for you.

In some cases you might check `ENDIAN_BOM` as an _optimization_, in case you can skip an `htol`/`ltoh` pass over an array. (It might be nice, in theory, to have optimized `broadcast`/`broadcast!`/`map` methods for `htol` and `ltoh` that can eliminate them in the common case where they are the identity. e.g. `x .= htol.(x)` in principle could be completely eliminated on a little-endian machine.)
