问题描述
我在 Perl 中使用 sprintf
将十进制数转换为其等效的十六进制数,如下所示:
my $positive = sprintf("X'%02X'",1); # X'01'
my $negative = sprintf("X'%02X'",-1); # X'FFFFFFFFFFFFFFFF'
为什么负数总是被符号扩展到数字的 8 字节表示,即使 sprintf
中指定的精度更小?
有没有办法避免这种情况,这样我就不必每次都对值进行子字符串化?即使我删除了 0
,也会出现相同的结果,如:sprintf("X'%2X'",-1)
。
解决方法
嗯,%x
专门接受一个无符号整数,所以当你给它一个有符号整数的位模式时,它会将所有这些位视为一个无符号位。输出的长度可能取决于您的编译器生成的数字有多大(尽管我猜现在大多数现代事物都是一样的)。 Perl 将其大部分数字存储为双精度数,因此这就是数字的大小。这是 Perl 公开底层架构的少数几个地方之一。
这意味着您需要自己处理符号并使用数字的绝对值:
sprintf( "%s%2x",($n < 0 ? '-' : ''),abs($n) );
至于 sprintf 字段说明符,您没有在那里指定精度。这是最小宽度。 %f
和 %g
说明符可能有最大小数位数,但整个字符串仍然可能溢出。
但是,事实证明你的问题是不同的。您希望从 -128 到 127 的值是它们的有符号整数形式。所以,-1 得到 FF
。你需要添加一点才能得到它。
my $s = sprintf( "%2x",$n );
$s = substr( $s,-2 ) if $n < 0;