2011-09-04 53 views
0

这里的存储方式是我用的程序:测试机器

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位CPU,64位操作系统上运行。这表明我的机器是小端的。为什么是第一个字节0xffffff89?为什么是ff?

回答

5

首先,你应该使用%x,因为这些不是指针。

%x指定符需要一个整数。因为您正在传入一个类型为'char'的值,该值是一个有符号类型,所以该值将被转换为一个整数并进行符号扩展。 http://en.wikipedia.org/wiki/Sign_extension

这基本上意味着它占用最重要的位并将其用于所有更高位。因此0x89 => 0b10001001,其中最高位'1'变为0xFFFFFF89。

正确的解决方案是指定一个'长度'参数选项。您可以在此处获得更多信息: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

'“%p”'期望一个'void *',而不是一个整数。任何指针都可以在大多数机器上工作,但在技术上是正确的(因为可变参数),所以在使用它时应该明确地施放。 –

+0

好点。我刚刚删除提及它。 – loganfsmyth

+1

此外,您需要使用'“%hhx”'来打印一个'unsigned char'值,而不是一个完整的'unsigned'值。 –

2

%p被询问printf to format it as an address,你actaully传递的值(* VAL)

在64位机器上的指针的地址是64位,所以printf的被添加FFFF到垫的字段

+0

为什么不为其他值做它?如0xffffff67。我使用%x代替%p,并得到相同的输出。 – Bruce

+0

这是未定义的行为,您要求它将地址打印为不是地址的值。所以它可能会使用堆栈中的下一个值,或者它可能会打印粉红色的独角兽 –

+0

为什么输出与%x相同? – Bruce

3

char是一个有符号类型,它在作为参数传递时被提升为int。此促销活动会延长签名。 0x89是char的负值,因此它会被符号扩展为0xffffff89。对于其他值不会发生这种情况,它们在大多数机器上不超过CHAR_MAX,127或0x7f。由于您使用了错误的格式说明符,您会对此行为感到困惑。

1

正如@马丁贝克特说,%pprintf要求打印指针,这相当于%#x%#lx(确切的格式取决于你的OS上)。

这意味着printf期待一个intlong(再次取决于操作系统),但你只用char提供这么值向上强制转换为适当的类型。

当你施放一个小签号码你必须做一些所谓的sign extension为了保值,一个更大的符号数。在0x89的情况下,会发生这种情况是因为符号位已设置,所以高位字节为0xff,因为它们很重要而被打印出来。

0x67,0x45,0x23的情况下,符号扩展不会发生,因为符号位未设置,因此高位字节为0,因此不会打印。

1

我测试字节序与条件((char)((int)511) == (char)255)。真的意味着小,虚假意味着大。

我已经在几个不同的系统,既少,大与优化关闭,以最大测试这一点,使用gcc。在我做的每一个测试中,我都得到了正确的结果。

在需要执行关键操作之前,可以将该条件放入应用程序中。如果你只想机制保障您正在使用正确的字节序为您的整个应用程序,你也可以使用一个静态断言方法如如下:

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 
+0

你能解释你答案的第一行吗? –