c编译器

时间:2017-03-08 07:08:45

标签: c memory-management global-variables

当我在main之外声明一些变量时,编译以某种特殊的方式存储它们。

int i=1,j=1;
void main(void)
{
     printf("%d\n%d",&i,&j);
}

如果ij都未初始化或等于0或等于某些正值,则它们将存储在内存中的连续地址空间中,而如果i=0j = some +ve integer那么他们的地址相距很远。

问题在于它们存储在连续的地址空间时会导致一些真正的性能问题,例如错误共享(看看here)。我已经了解到,为防止这种情况发生,变量的地址之间应该有一些空格,这些地址会在i=0j=any +ve value时自动提供。

现在,我想要了解的是:

  • 为什么编译器只有在初始化为0且其他初始化为正值的情况下才将变量存储到非连续地址,并且
  • 我如何有意识地执行编译器自动执行的操作,即将变量分配给相当分离的地址空间。

(使用devcpp gcc 4.9.2)

2 个答案:

答案 0 :(得分:3)

假设您的意思是SELECT OBJ.OBJ_NAME FROM OBJ,OBI,OIU,OST,USR WHERE OBJ.OBJ_KEY=OBI.OBJ_KEY AND OBI.OBI_KEY=OIU.OBI_KEY AND OIU.USR_KEY=USR.USR_KEY AND OIU.OST_KEY=OST.OST_KEY AND OST.OBJ_KEY=OBJ.OBJ_KEY AND USR.USR_LOGIN='[Insert User Login here]' AND OST.OST_STATUS IN ('Enabled','Provisioned'); ,请注意以下事项:

  1. C规范没有规定在连续内存中分配变量。
  2. 通常使用printf("%p, %p\n",(void *)&i,(void *)&j);初始化的全局变量保存在BSS section(这是数据部分的一部分)中以保存二进制大小。其他全局变量保留在data section的其余部分。 (取决于实施细节,不是C规范要求)
  3.   

    我如何有意识地执行编译器自动执行的操作?

    这是编译器特定的问题,您的编译器文档应该包含对此的答案。

答案 1 :(得分:2)

那里有一个问题,

        ID COL1                    COL2                    D
---------- ----------------------- ----------------------- -
         1 ABC DEF                 DEF ABC                 Y
         2 ABC DEF                 GHI ABC                 N
         3 ABCD EFGH IJKL MNOP     IJKL MNOP ABCD EFGH     Y
         4 ABCD EFGH IJKL MNOP     IJKL QRST EFGH ABCD     N
         5 ABC ABC DEF             DEF ABC DEF             N
         6 AAA BBB CCC DDD EEE     AAA BBB CCC DDD         N
         7 AAA BBB CCC DDD EEE     AAA BBB CCC DDD EEE     Y
         8 XXX YYYY ZZZ AAA BBB    AAA BBB XXX ZZZ YYYY    Y
         9 A B C D E F G H I J K L L K J I H G F E D C B A Y
        10 AA BB CC DD EE          AA BB CC DD FF          N

10 rows selected.

SQL> 

调用undefined behavior。因此,输出无论如何都不合理。您需要使用 printf("%d\n%d",&i,&j); 格式说明符将相应的参数强制转换为%p以打印指针。

尽管如此,C标准既没有施加任何约束,也没有提供关于变量在何处以及如何存储在内存中的任何指导。由编译器实现决定如何将不同的变量放在内存中。您需要检查正在使用的编译器的文档,以找出编译器遵循的规则。

以通用方式详细说明,object file由许多细分组成,例如

  • 标题(描述和控制信息)
  • 代码段(“文本段”,可执行代码)
  • 数据段(初始化静态变量)
  • 只读数据段(rodata,初始化静态常量)
  • BSS段(未初始化的静态数据,包括变量和常量)
  • 外部定义和链接参考
  • 重新安置信息
  • 动态链接信息
  • 调试信息

由编译器决定每个段使用的地址空间(范围/值)。

根据规则,

  • 未初始化并使用(void *)初始化的全局变量(即具有静态存储持续时间)放在0段中。
  • 使用非零值初始化的变量放在.bss

所以,公平地说两个不同段的两个变量的地址不会是连续的。

现在,你的观察结束了。

  

如果.datai都未初始化或等于0或等于某些正值,则它们将存储在内存中的连续地址空间

是的,然后所有这些都转到j.bss,编译器通常选择将它们一个接一个地放置。

  

而如果.datai=0整数,则他们的地址相隔很远。

这也适用,两个变量现在都放在不同的段中。