当我在main外声明某些变量时,以某种特殊的方式存储它们。
int i=1,j=1;
void main(void)
{
printf("%dn%d",&i,&j);
}
如果i
和j
均未初始化或等于0或等于某些正值,则它们存储在内存中的连续地址空间中,而如果i=0
和j = some +ve integer
,则其地址会被相当较大的距离分开。
问题是,当它们存储在连续地址空间上时,会导致一些实际的性能问题,例如false共享(请在此处查看)。我了解到,为了防止这种情况,变量的地址之间应该有一些空间,而i=0
和j=any +ve value
。
现在,我想了解的是:
- 为什么仅当一个初始化为0,而另一个初始化为正值时,编译器将变量存储到非连续地址,而
- 我该如何有意执行编译器自动执行的操作,即将变量分配给相当分开的地址空间。
(使用DEVCPP GCC 4.9.2)
假设您的意思是printf("%p, %pn",(void *)&i,(void *)&j);
,请注意以下内容:
- C规格不要求在连续内存中分配变量。
- 通常以
0
初始化的Globals保存在BSS部分(这是数据部分的一部分),以节省二进制大小。其他全球群体将保存在数据部分。(取决于实施细节,而不是C规格规定)
我如何有意自动执行编译器?
这是编译器的特定问题,您的编译器文档可能包含答案。
那里一个问题,
printf("%dn%d",&i,&j);
调用不确定的行为。因此,输出不能以任何方式被证明是合理的。您需要使用 %p
格式指定器和将相应的参数施加到(void *)
以打印指针。
也就是说,C标准既没有施加任何约束,也没有提供有关将变量存储在存储器中的何处和如何存储的指南。由编译器实现决定如何在内存中放置不同的变量。您需要检查使用中的编译器的文档,以找出您的编译器所遵循的规则。
要以通用方式详细说明,一个对象文件由许多段组成,例如
- 标题(描述性和控制信息)
- 代码段("文本段",可执行代码)
- 数据段(初始化的静态变量)
- 仅阅读数据段(rodata,初始化的静态常数)
- BSS段(非初始化的静态数据,变量和常数)
- 链接的外部定义和参考
- 搬迁信息
- 动态链接信息
- 调试信息
,由编译器决定要用于每个段的地址空间(范围/值)。
根据规则,
- 全局变量(即具有静态存储持续时间)剩余的不定原始化和用
0
初始化的.bss
段。 - 以非零值初始化的变量放在
.data
段
中
因此,公平地说,与两个不同段有关的两个变量的地址不会连续。
现在,您的观察结果已签出。
如果
i
和j
均未初始化或等于0或等于某些正值,则它们存储在内存中的连续地址空间
是的,然后所有这些都转到.bss
或.data
,然后编译器选择将它们放置一个,通常是一个。
,而如果
i=0
和j = some +ve
整数,则它们的地址被相当大的距离分开。
这也是正确的,两个变量现在都放在不同的段中。