简体   繁体   中英

Rust: How to cast from a signed integer type to a larger signed integer type *without* sign extension

Suppose we have an i8 which we want to cast to an i16 without sign extension.

We can't do us a simple as cast, as this will sign extend.

println!("{:b}", -128i8); // 10000000 <- we want this zero-extended in an i16.
println!("{:b}", -128i8 as i16);  // 1111111110000000 sign extended :(

We cannot transmute, because the types are of different size:

println!("{:b}", unsafe {mem::transmute::<_, i16>(128i8)});
// ^ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types :(

The best I've come up with is the following convoluted casting chain:

println!("{:b}", -128i8 as u8 as u16 as i16); // 10000000 :), but :( because convoluted.

The intermediate cast to u8 means that casting up to a u16 will zero-extend instead of sign extend, then casting from u16 to i16 is fine, as the types are the same size and no extension is required.

But there must be a better way? Is there?

Keeping in mind that for this case (printing the number's bits) you can just do the unsigned conversion.

However in general Rust doesn't really like doing implicit conversions, but you can always write

let n : i8 = -128;
let m : i32 = n as u8 as i32;

You pretty much can't get better than this in general, as double casting is common in fields like changing pointer's types. Also consider not using unsafe when the operation you are doing can be done safely without downsides (aside from maybe a slight code smell).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM