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

c中的整数如何存储在内存中?,c,memory,C,Memory,我认为C中的INT首先以最高有效位存储,例如,数字5将是0…0101。我想我可以通过强制C让我假装一个特定的内存地址是一个int,然后像一个int那样添加到位中来操纵特定的位 我尝试在内存中设置0位0,然后尝试将255添加到不同的内存地址,这似乎就像最低有效位存储在内存中的最高有效位之前一样,因为当我在内存地址中添加1并更改位时,我得到的是一个较大的数字,而不是较小的数字。如果最高有效位较早地存储在内存中,则将255添加到内存地址上1字节以上不会影响原始地址的数字,因为最后8位是下一个int的开

我认为C中的INT首先以最高有效位存储,例如,数字
5
将是
0…0101
。我想我可以通过强制C让我假装一个特定的内存地址是一个
int
,然后像一个
int
那样添加到位中来操纵特定的位

我尝试在内存中设置0位0,然后尝试将
255
添加到不同的内存地址,这似乎就像最低有效位存储在内存中的最高有效位之前一样,因为当我在内存地址中添加1并更改位时,我得到的是一个较大的数字,而不是较小的数字。如果最高有效位较早地存储在内存中,则将
255
添加到内存地址上1字节以上不会影响原始地址的数字,因为最后8位是下一个
int
的开始。我想知道我是否正确地解释了这一点,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
实际产量:

4
255,0
65280,0
16711680,0
-16777216,0
12784560
12784564
我认为c中的INT首先以最高有效位存储,例如,数字5将是0…0101

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

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

现在很多商品PC都是这样,所以正好相反(最低有效字节优先)。你可能就是这样

请注意,endianness谈论的是字节,而不是位


最好不要试图像这样操纵数据。使用该语言,使用不关心尾数的逻辑运算。

代码中存在一些问题:

  • 位和字节之间似乎有些混淆。计算机内存可寻址为字节,在当前架构中通常由8位组成

  • 您不应该将指针强制转换为
    int
    int
    可能没有足够的范围来容纳指针的值。将指针转换为
    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
    打印
    大小\u t
    或将
    大小\u t
    转换为
    int

  • 指针应转换为
    (void*)
    ,并使用
    %p
    打印
  • 如果以十六进制打印
    int
    值,更改的效果会更明显
以下是修改后的版本:

#包括
#包括
int main(){
//获取4个内存地址,每个地址都有足够的空间容纳2 int,初始化为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));
((无符号字符*)x)[0]=255;//添加到x的内存地址
((unsigned char*)y)[1]=255;//在y上加1字节
((unsigned char*)z)[2]=255;//在z上添加2个字节
((unsigned char*)a)[3]=255;//从
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]);
返回0;
}
输出:

4 000000ff,00000000 -- 255,0 0000ff00,00000000 -- 65280,0 00ff0000,00000000 -- 16711680,0 ff000000,00000000 -- -16777216,0 0x7fd42ec02630 0x7fd42ec02634 4. 000000ff,00000000--255,0 0000FF0000000000--65280,0 00FF000000000000--16711680,0 FF00000000000000--16777216,0 0x7fd42ec02630 0x7fd42ec02634 从上述输出中,我们可以看到:

  • 类型
    int
    有4个字节
  • 指针使用8个字节(我的环境是64位的,与您的不同)
  • int
    首先以最低有效字节存储,与您的相同,这被称为小端结构
你期待的是相反的大端体系结构,这在当前的台式机和笔记本电脑上非常罕见,但在嵌入式体系结构和移动电话上非常常见

这两种方法各有优缺点。C透明地支持这两者,因此大多数程序员不知道这些复杂之处,但在某些情况下,理解这些实现细节非常有用:

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

您必须考虑特定于平台的Endianness,有关更多详细信息,请参阅下面的链接。我真的不明白您在这里想要实现什么。为什么所有的强制转换?@Max这取决于编译器、机器或其他东西吗?@LightnessRacesinOrbit如果我没有先将内存地址强制转换为int,那么+1将被解释为4字节而不是1字节,但随后我必须将其强制转换回int*并取消引用,这样它才是一个合适的左值,我可以将255赋给torouble,这就是“假装”违反语言规则。至少它将在C++中;公平地说,我并不是100%相信C。