c中的整数如何存储在内存中?

时间:2019-04-05 09:00:16

标签: c memory

我认为C中的整数首先以最高有效位存储,例如,数字5将是0...0101。我以为我可以通过强制C让我假装一个特定的内存地址是int并像在int一样向其中添加位来操纵特定位。

我试图在内存中设置0的0位,然后尝试将255添加到不同的内存地址,这似乎工作起来好像最低有效位先于最高有效位存储在内存中,因为当我在我的内存地址中加1并更改位,然后得到一个更大的数字,而不是一个较小的数字。如果最高有效位较早地存储在内存中,则将255添加到比其高1个字节的内存地址中完全不会影响原始地址的编号,因为后8位是下一个{{ 1}}。我想知道我是否正确地解释了这一点,并且整数首先以最低有效位存储。

int

预期输出:

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main() {
    int *x = malloc(8); //getting 4 memory addresses
    int *y = malloc(8);
    int *z = malloc(8);
    int *a = malloc(8);

    x[0] = 0; //setting 64 bits past memory addresses to 0s
    x[1] = 0;
    y[0] = 0;
    y[1] = 0;
    z[0] = 0;
    z[1] = 0;
    a[0] = 0;
    a[1] = 0;

    *((int*)((int)x)) = 255; //adding to x's memory address
    *((int*)((int)y + 1)) = 255; //adding 1 byte over from y
    *((int*)((int)z + 2)) = 255; //adding 2 bytes over from z
    *((int*)((int)a + 3)) = 255; //adding 3 bytes over from a

    printf("%d\n", sizeof(int));
    printf("%d,%d\n", x[0], x[1]);
    printf("%d,%d\n", y[0], y[1]);
    printf("%d,%d\n", z[0], z[1]);
    printf("%d,%d\n", a[0], a[1]);

    printf("%d\n", x);
    printf("%d\n", &x[1]);
    return 0;
}

实际输出:

4
255,0
0,-16777216
0,16711680
0,65280
12784560
12784564

2 个答案:

答案 0 :(得分:5)

  

我认为c中的int首先存储了最高有效位,例如,数字5将为0 ... 0101

不,这取决于您的平台和工具链,而不取决于C。

您描述的方案(几乎)被称为 big-endian

当今许多商用PC是little-endian,所以相反(最低有效字节在前)。您可能就是这种情况。

请注意,字节序是指字节,而不是位。

最好不要尝试像这样操作数据。使用该语言,使用不关心字节序的逻辑运算。

答案 1 :(得分:0)

您的代码中存在一些问题:

  • 字节之间似乎有些混淆。计算机内存可按字节寻址,在当前体系结构上通常包含8位。

  • 您不应将指针强制转换为intint可能没有足够的范围来容纳指针的值。将指针转换为unsigned char *以修补单个字节,但要注意,由于别名规则,这可能不会产生预期的结果:

    ((unsigned char *)x)[0] = 255; //adding to x's memory address
    ((unsigned char *)y)[1] = 255; //adding 1 byte over from y
    ((unsigned char *)z)[2] = 255; //adding 2 bytes over from z
    ((unsigned char *)a)[3] = 255; //adding 3 bytes over from a
    
  • 类似地,您应该使用%zu打印size_t或将size_t转换为int

  • 指针应强制转换为(void*),并用%p打印。
  • 如果以十六进制打印int值,更改的效果将更加明显。

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>

int main() {
    // getting 4 memory addresses, each with enough space for 2 int, initialized to 0
    int *x = calloc(2, sizeof(int));
    int *y = calloc(2, sizeof(int));
    int *z = calloc(2, sizeof(int));
    int *a = calloc(2, sizeof(int));

    ((unsigned char *)x)[0] = 255; //adding to x's memory address
    ((unsigned char *)y)[1] = 255; //adding 1 byte over from y
    ((unsigned char *)z)[2] = 255; //adding 2 bytes over from z
    ((unsigned char *)a)[3] = 255; //adding 3 bytes over from a

    printf("%d\n", (int)sizeof(int));
    printf("%08x,%08x -- %d,%d\n", x[0], x[1], x[0], x[1]);
    printf("%08x,%08x -- %d,%d\n", y[0], y[1], y[0], y[1]);
    printf("%08x,%08x -- %d,%d\n", z[0], z[1], z[0], z[1]);
    printf("%08x,%08x -- %d,%d\n", a[0], a[1], a[0], a[1]);

    printf("%p\n", (void *)x);
    printf("%p\n", (void *)&x[1]);
    return 0;
}

输出:

4
000000ff,00000000 -- 255,0
0000ff00,00000000 -- 65280,0
00ff0000,00000000 -- 16711680,0
ff000000,00000000 -- -16777216,0
0x7fd42ec02630
0x7fd42ec02634

从上面的输出中,我们可以看到:

  • 类型int有4个字节
  • 指针使用8个字节(我的环境是64位,与您的环境不同)
  • int的最低有效字节与您存储的最低有效字节相同,这被称为
  • little-endian体系结构。

您期望的是相反的 big-endian架构,这种架构在当前的台式机和笔记本电脑上很少见,但在嵌入式架构和手机上很常见。

两种方法都有优点和缺点。 C透明地支持两者,因此大多数程序员并不了解这些复杂性,但是了解这些实现细节在某些情况下非常有用:

  • 系统编程,底层编程,设备驱动程序开发
  • 图像处理
  • 读写二进制文件和流,
  • 处理二进制数据的网络传输,尤其是在不同设备之间的传输。
  • 与其他编程语言接口,编写库等。