Skip to content

Listing 2.4, run: base 2, 8 and 16

Rust in Action, run › Chapter 2 › §2.3.2 · the book's file: ch2/ch2-non-base2.rs ↗

Level: 101 · a companion to Rust in Action, chapter 2

One line: On rustc 1.98.0, listing 2.4's four output lines match the book byte for byte, and so does the positional arithmetic after it. The section leaves out three traps: 036 without the o is thirty-six, 0x1f32 is the integer 7986 rather than a float, and from_str_radix does not accept the prefix you write in source.

What the listing prints

ch2-non-base2.rs, run on rustc 1.98.0
base 10: 3 30 300
base 2:  11 11110 100101100
base 8:  3 36 454
base 16: 3 1e 12c

Seven claims, run

Verified output of non_base2.rs — regenerated by tools/run_examples.py, never hand-typed.

1. 3 30 300
   0x12C == 0x12c: true; their types: i32 i32 i32
2. 2*1 + 1*1 = 3, 8*3 + 1*6 = 30, 256*1 + 16*2 + 1*12 = 300
3. 036 = 36, 0o36 = 30
4. 0x1f32 = 7986, an i32; 0x1_u32 = 1
5. 100101100 0b100101100 | 454 0o454 | 12c 12C 0x12c 0x012c
6. Ok(300) | Err(ParseIntError { kind: InvalidDigit })
7. -3_i8: 11111101 fd
  1. 0b, 0o and 0x change how the number is written, not its type. All three literals are i32, the fallback, like any unsuffixed integer. Hex digits may be either case; the prefix letter is always lowercase. → The prefix
  2. The book's arithmetic is right. Each digit is multiplied by a power of the base: 300 = 1·16² + 2·16¹ + 12·16⁰, where the hex digit C stands for 12. → Why hexadecimal
  3. A leading zero on its own is not octal. 036 is thirty-six. In C, the same literal is octal and means thirty, and rustc 1.98.0 prints no warning about it. → A leading zero on its own means nothing
  4. A hex literal swallows a suffix made of hex digits. In 0x1f32, the letters f, 3 and 2 are hex digits, so the whole thing is one integer, 7986. It is not a float, and Rust has no hex float literals anyway (transcript below). Integer suffixes start with i or u, which are not hex digits, so 0x1u32 and 0x1_u32 mean what they look like. → The suffix is the type
  5. In println!, a letter picks the base, # adds the prefix, and the width includes it. The book shows {:b}, {:o} and {:x}. {:X} prints uppercase digits, {:#x} prints 0x12c, and {:#06x} pads to six characters, prefix included: 0x012c. → Rust's four spellings, The format mini-language
  6. Parsing a number back takes the base as an argument; the prefix is not accepted. i32::from_str_radix("12C", 16) is Ok(300), and the same call on "0x12C" is InvalidDigit. → from_str_radix takes a radix, not a prefix
  7. A negative number prints its two's-complement bits. {:b} of -3_i8 is 11111101, with no minus sign, and {:x} is fd. → Hex of a signed integer is two's complement

What the compiler refuses

A digit that is too big for the base is caught while the literal is being read:

Abridged — rustc 1.98.0 output for binary_digit_two.rs
error: invalid digit for a base 2 literal
 --> binary_digit_two.rs:2:20
  |
2 |     let three = 0b12;
  |                    ^
Abridged — rustc 1.98.0 output for octal_digit_eight.rs
error: invalid digit for a base 8 literal
 --> octal_digit_eight.rs:2:19
  |
2 |     let eight = 0o8;
  |                   ^

And the only base a float literal can be written in is decimal:

Abridged — rustc 1.98.0 output for hex_float.rs
error: hexadecimal float literal is not supported
 --> hex_float.rs:2:13
  |
2 |     let x = 0x1.8;
  |             ^^^^^

Concepts, keywords, topics

In the listing Keyword or concept Lesson here Normative source
0b11, 0o36, 0x12C numeric literal prefix, radix Writing a number down · Why hexadecimal Integer literals ↗
{:b}, {:o}, {:x} formatting traits Binary, Octal, LowerHex The format mini-language Formatting traits ↗
the digits of 0x12C positional notation, nibble Why hexadecimal · Bit flags —
reading 12c back from_str_radix Why hexadecimal · Parsing a string i32::from_str_radix ↗
a negative value in base 2 two's complement Meet the byte Integer types ↗

The glossary defines hexadecimal, nibble, radix, numeric literal prefix, from_str_radix and two's complement.

See also

Po polsku

Listing 2.4 wypisuje na rustc 1.98.0 co do bajtu to, co pokazuje książka, a rachunek pozycyjny po nim się zgadza (0x12C = 1·16² + 2·16 + 12 = 300). Przedrostek (0b, 0o, 0x) zmienia tylko zapis liczby, nie typ — wszystkie trzy literały są i32.

Trzy pułapki, których książka nie wspomina. Samo zero na początku nic nie znaczy: 036 to trzydzieści sześć, choć w C to liczba ósemkowa równa 30. Literał szesnastkowy „połyka” przyrostek złożony z cyfr szesnastkowych: 0x1f32 to liczba całkowita 7986, a nie f32 (literałów zmiennoprzecinkowych w zapisie szesnastkowym Rust w ogóle nie ma). I from_str_radix przyjmuje podstawę jako argument, a przedrostka nie rozumie: "0x12C" to błąd InvalidDigit. Liczba ujemna wypisana binarnie pokazuje kod uzupełnień do dwóch (two's complement): -3_i8 to 11111101.

Szukaj po polsku: system dwójkowy ósemkowy szesnastkowy · kod uzupełnień do dwóch · rust from_str_radix 0x prefix · rust {:#x} format