这是我使用的程序:
int hex = 0x23456789;
char * val = &hex;
printf("%p\n",hex);
printf("%p %p %p %p\n",*val,*(val+1),*(val+2),*(val+3));
这是我的输出:
0x23456789
0xffffff89 0x67 0x45 0x23
我正在使用64位操作系统的64位CPU。这表明我的机器是小端。为什么第一个字节是0xffffff89?为什么选择ff?
答案 0 :(得分:5)
首先,您应该使用%x,因为它们不是指针。
%x说明符期望一个整数。因为传入的值为'char'(有符号类型),所以该值将转换为整数并进行符号扩展。 http://en.wikipedia.org/wiki/Sign_extension
这实质上意味着它需要最高位并将其用于所有较高位。所以0x89 => 0b10001001,其最高位为'1',变为0xFFFFFF89。
正确的解决方案是指定'length'参数选项。您可以在此处获得更多信息:Printf Placeholders基本上,在'%'和'x'之间,您可以添加额外的参数。 'hh'表示您传递的是char值。
int hex = 0x23456789;
char *val = (char*)&hex;
printf("%x\n",hex);
printf("%hhx %hhx %hhx %hhx\n", val[0], val[1], val[2], val[3]);
答案 1 :(得分:3)
char是一个带符号的类型,当作为参数传递时,它会被提升为int。此促销会导致签名延期。 0x89是char的负值,因此符号扩展为0xffffff89。对于其他值,这不会发生,它们在大多数机器上不会超过CHAR_MAX,127或0x7f。您对这种行为感到困惑,因为您使用了错误的格式说明符。
答案 2 :(得分:2)
%p正在询问printf to format it as an address,您实际上正在传递值(* val)
在64位机器上,指针地址是64位,所以printf正在添加ffff来填充字段
答案 3 :(得分:1)
正如@Martin Beckett所说,%p
要求printf
打印一个指针,该指针相当于%#x
或%#lx
(具体格式取决于您的操作系统)。
这意味着printf
期望int
或long
(再次取决于操作系统),但您只提供char
,因此值为up-cast到适当的类型。
当您将较小的有符号数转换为较大的有符号数时,您必须执行一个名为sign extension的操作以保留该值。在0x89
的情况下,这是因为符号位已设置,因此高位字节为0xff
并且因为它们很重要而被打印。
对于0x67
,0x45
,0x23
符号扩展不会发生,因为符号位未设置,因此高位字节为0,因此不会打印。< / p>
答案 4 :(得分:1)
我使用条件((char)((int)511) == (char)255)
测试endian-ness。真意味着很少,虚假意味着很大。
我已经在几个单独的系统上进行了测试,无论是小还是大,使用gcc优化关闭和最大化。在我做过的每一项测试中,我都得到了正确的结果。
您可以在需要执行关键字操作之前将该条件放在应用程序的if中。如果您只想保证您在整个应用程序中使用正确的字节序,则可以改为使用静态断言方法,如下所示:
extern char ASSERTION__LITTLE_ENDIAN[((char)((int)511) == (char)255)?1:-1];
如果系统不是小端并且拒绝编译,那么全局范围中的那一行将产生编译错误。如果没有错误,它会完美地编译,就好像该行不存在一样。我发现错误消息非常具有描述性:
error: size of array 'ASSERTION__LITTLE_ENDIAN' is negative
现在,如果您偏执狂编译器优化我的实际检查,您可以执行以下操作:
int endian;
{
int i = 255;
char * c = &i;
endian = (c[0] == (char)255);
}
if(endian) // if endian is little
这个宏很好地压缩了这个宏:
#define isLittleEndian(e) int e; { int i = 255; char * c = &i; e = (c[0] == (char)255); }
isLittleEndian(endian);
if(endian) // if endian is little
或者如果你使用GCC,你可以逃脱:
#define isLittleEndian ({int i = 255; char * c = &i; (c[0] == (char)255);})
if(isLittleEndian) // if endian is little