如果有的话,如何将变量彼此“接近”存储在C中的规则是什么?

时间:2019-04-15 12:12:37

标签: c memory

我知道对于结构

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。

我尝试将这两个数组存储在main函数之外,而不是存储在struct

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。

我意识到编译器可能会根据我控制范围之外的一些复杂因素来选择将变量存储在何处,但是是否有任何规则保证,其中两个变量将相互存储,好像似乎有结构?

2 个答案:

答案 0 :(得分:3)

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

关于结构,C standard的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]);
}

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

答案 1 :(得分:0)

absequence的元素必须是连续的。此外,a的第一个元素的地址必须与struct的实例的地址相同。

实现可以在ab之间以及b之后添加填充

您不能使用指针算术来确定ab之间是否没有填充:指针算术的行为仅在范围内定义。因此,您提供的运行i最多5个代码的行为是不确定的,因此您不能将其用于任何可靠的目的。

由于将指针设置为数组(或对象,但此处不相关)之外的指针是合法的,因此表达式(void*)(&a + 1)是有效的,因此可以使用测试

(void*)(&a + 1) == (void*)&b;

测试ab的连续性。 (确认@EricPostpischil。)