首页 > 解决方案 > 如果有的话,在 C 中如何“接近”其他变量存储的规则是什么?

问题描述

我知道对于一个结构

struct sequences{
    int a[3];
    int b[3];
} sequence = {{1,2,3},{4,5,6}};

a 和 b 彼此相邻存储,即如果我这样做

int i;
for(i=0; i<6; ++i){
    printf("%d", sequence.a[i]);
}

我将得到输出 123456。

我尝试将这两个数组存储在主函数之外,但不在结构中

int a[3] = {1,2,3};
int b[3] = {4,5,6};

当我尝试同样的事情时,

    for(i=0; i<6; ++i){
        sum = sum + a[i];
    }

我得到输出 123045。因此,如果不在结构中,显然不能保证它们彼此相邻存储。

如果我改为在它之后存储一个数组和一个整数,它们似乎总是在内存中彼此之后,即

int a[3] = {1,2,3};
int x = 1000;

    for(i=0; i<4; ++i){
        printf("%d", a[i]);
    }

给出 1231000。

我意识到编译器可能会根据我无法控制的一些复杂因素来选择存储变量的位置,但是是否有任何规则可以保证两个变量相互关联的存储位置,就像结构似乎存在一样?

标签: cmemory

解决方案


C 标准仅保证结构的非位域成员按顺序存储在内存中,元素之间有可选的填充,并且数组的成员按顺序存储而没有填充。

关于结构,C 标准的第 6.7.2.1p15 节规定:

在结构对象中,非位域成员和位域所在的单元的地址按声明顺序递增。一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头。

不能保证将一个相关的变量放在内存中的另一个变量上。

此外,当你这样做时:

struct sequences{
    int a[3];
    int b[3];
} sequence = {{1,2,3},{4,5,6}};
...

int i;
for(i=0; i<6; ++i){
    printf("%d", sequence.a[i]);
}

您调用未定义的行为是因为您的索引超出了数组成员的末尾ab在这种情况下,实现不需要读取 的元素。在仍然符合标准的同时,最好的办法就是比较&sequence.a[3] == &sequence.b[0]


推荐阅读