测试机器的字节顺序

时间:2011-09-04 17:23:24

标签: c endianness

这是我使用的程序:

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?

5 个答案:

答案 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期望intlong(再次取决于操作系统),但您只提供char,因此值为up-cast到适当的类型。

当您将较小的有符号数转换为较大的有符号数时,您必须执行一个名为sign extension的操作以保留该值。在0x89的情况下,这是因为符号位已设置,因此高位字节为0xff并且因为它们很重要而被打印。

对于0x670x450x23符号扩展不会发生,因为符号位未设置,因此高位字节为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