How to format signed integer in hexadecimal representation with character support?

My original intention was to convert the signed primitive number to its hexadecimal representation in such a way as to preserve the sign of the number. It turns out that current implementations of LowerHex , UpperHex and siblings for signed primitive integers will simply treat them as unsigned. No matter what additional formatting flags I add, these implementations seem to simply reinterpret the number as its unsigned counterpart for formatting purposes. ( Playground )

 println!("{:X}", 15i32); // F println!("{:X}", -15i32); // FFFFFFF1 (expected "-F") println!("{:X}", -0x80000000i32); // 80000000 (expected "-80000000") println!("{:+X}", -0x80000000i32); // +80000000 println!("{:+o}", -0x8000i16); // +100000 println!("{:+b}", -0x8000i16); // +1000000000000000 

The documentation in std::fmt is unclear whether this should happen or even true, and UpperHex (or any other formatting character) does not mention that signed integer implementations interpret the numbers as unsigned. There seems to be no related issues in the Rust GitHub repository.

Ultimately, it would be possible to implement certain functions for the task (as shown below), and a failed flaw is not very compatible with the formatter API.

 fn to_signed_hex(n: i32) -> String { if n < 0 { format!("-{:X}", -n) } else { format!("{:X}", n) } } assert_eq!(to_signed_hex(-15i32), "-F".to_string()); 

Is this behavior of signed signed types? Is there a way to do this formatting procedure while still sticking to the standard Formatter ?

+5
source share
1 answer

Is there a way to do this formatting procedure while still sticking to the standard Formatter ?

Yes, but you need to create a new type to provide an excellent implementation of UpperHex . Here's an implementation that takes into account the + , # and 0 flags (and maybe more, I haven't tested):

 use std::fmt::{self, Formatter, UpperHex}; struct ReallySigned(i32); impl UpperHex for ReallySigned { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let prefix = if f.alternate() { "0x" } else { "" }; let bare_hex = format!("{:X}", self.0.abs()); f.pad_integral(self.0 >= 0, prefix, &bare_hex) } } fn main() { for &v in &[15, -15] { for &v in &[&v as &UpperHex, &ReallySigned(v) as &UpperHex] { println!("Value: {:X}", v); println!("Value: {:08X}", v); println!("Value: {:+08X}", v); println!("Value: {:#08X}", v); println!("Value: {:+#08X}", v); println!(); } } } 
+4
source

Source: https://habr.com/ru/post/1269137/


All Articles