在C中打印整数的实际位表示

时间:2018-07-25 11:03:57

标签: c

我想在C中打印整数的实际位表示形式。这是我发现的两种方法。

第一

union int_char {
    int val;
    unsigned char c[sizeof(int)];
} data;

data.val = n1;
// printf("Integer: %p\nFirst char: %p\nLast char: %p\n", &data.f, &data.c[0], &data.c[sizeof(int)-1]);

for(int i = 0; i < sizeof(int); i++)
    printf("%.2x", data.c[i]);
    printf("\n");

第二:

for(int i = 0; i < 8*sizeof(int); i++) {
    int j = 8 * sizeof(int) - 1 - i;
    printf("%d", (val >> j) & 1);
}
printf("\n");

对于第二种方法,输出为0000000202000000。我还尝试了其他数字,似乎字节在两个中交换了。哪个是正确的?

4 个答案:

答案 0 :(得分:3)

欢迎来到异域风情的字节序世界。

因为我们先写最高有效位的数字,所以您可能会想到最高有效字节存储在低位地址。

建造计算机的电气工程师更具想象力。

Someimes首先存储最高有效字节,但在您的平台上存储最低有效字节。

甚至在一些平台上,它们都有点混杂-但是您在实践中很少会遇到这些情况。

因此,我们大部分讨论的是大端和小端。这是关于《格列佛游记》的笑话,关于煮鸡蛋的哪端开始毫无争议。这本身就是基督教教会中一些争执的讽​​刺。但是我离题了。

因为您的第一个代码片段将其值看成是它遇到的一系列字节,然后按字节序排列。

但是由于>>被定义为对位进行操作,因此它被实现为“逻辑上”工作,而与实现无关。

C不定义字节顺序是正确的,因为不支持选择的模型C的硬件将承受无休止地无休止地拖移字节的开销。

可悲的是,没有内置标识符可以告诉您模型是什么-尽管可以找到确实存在的代码。

如果(a)如上所述您想要将整数类型分解为字节并对其进行操作,或者(b)收到用于包含多字节结构的其他平台的文件,这将与您相关。

Unicode在UTF-16和UTF-32中提供了一种称为BOM(字节顺序标记)的东西。 实际上,使用UTF-8的一个很好的理由(其中有很多)是问题消失了。因为每个组件都是一个字节。

脚注: 在我还没有讲完整故事的评论中已经相当清楚地指出了这一点。 C语言规范允许使用不止一种整数表示形式,尤其是带符号整数。具体是有符号幅度,二进制补码和一个补码。

它还允许“填充位”不代表值的一部分。

因此,原则上,在处理字节序时,我们需要考虑表示形式。

原则上。所有现代计算机都使用二进制补码,并且使用其他任何东西的现存机器都很少见,除非您有真正的支持此类平台的要求,否则建议您使用二进制补码系统。

答案 1 :(得分:0)

这取决于您对“正确”的定义。

第一个将完全按照存储在内存中的方式打印数据,所以我敢打赌,这就是您可能会意外使用的02000000的原因。 *)恕我直言,这是正确之一。可以通过直接使用unsigned char *来别名来简化操作(始终允许使用char指针作为其他任何指针的别名,实际上,访问表示形式是标准中提到的char指针的用例) ):

int x = 2;
unsigned char *rep = (unsigned char *)&x;
for (int i = 0; i < sizeof x; ++i) printf("0x%hhx ", rep[i]);

第二个仅打印值位 **),并按从最高有效字节到最低有效字节的顺序进行处理。我不称其为正确,因为它还假定字节有8位,并且因为所使用的移位是为负数实现定义的。 ***)此外,如果您真的想查看表示形式,那么仅忽略填充位似乎也不正确。

编辑:与此同时,commented by Gerhardh的第二个代码不是逐字节打印 ,而是逐点打印 。因此,您声称看到的输出是不可能的。仍然是相同的原理,它只打印值位并从最高有效位开始。


*)您在“小端”计算机上。在这些计算机上,最低有效字节首先存储在内存中。进一步了解Endianness on wikipedia

**)C中类型的表示形式也可能具有填充位。某些类型不允许包含填充(例如char),但允许int包含填充。第二个选项不是别名char,因此填充位保持不可见。

***)此代码的正确版本(用于打印所有值位)必须 a)正确确定值位的数量({{1} }是错误的,因为字节(8 * sizeof int的位数可能超过8位,即使char也是错误的,因为这也会计算填充位(如果存在),并且 b)避免使用通过首先转换为CHAR_BIT * sizeof int实现定义的转换行为。例如,可能看起来像这样:

unsigned

有关此奇怪宏的说明,请参见this answer

答案 2 :(得分:0)

正确的十六进制字符串表示形式是00000002,就像用十六进制重新声明整数一样。

int n = 0x00000002; //n=2

或者您将整数打印为十六进制时所获得的位置:

printf("%08x", n);

但是当打印整数字节后接一个字节时,还必须考虑endianess,它是多字节整数的字节顺序:

在大字节序系统(某些UNIX系统使用它)中,这4个字节在内存中的顺序为:

 00 00 00 02 

在小端系统(大多数操作系统)中,字节在内存中的排列顺序为:

 02 00 00 00

答案 3 :(得分:0)

第一个按其在内存中出现的顺序打印表示整数的字节。具有不同字节序的平台将以不同的方式存储整数,从而打印出不同的结果。

第二个先打印组成整数值的最高有效位。此结果与字节顺序无关。结果也与>>操作符如何用于带符号的int无关,因为它不会查看可能受实现影响的位。

第二个是与“在C中打印整数的实际位表示形式”问题更好的匹配。尽管有很多歧义。