嵌入式linux c 学习笔记8-变量布局

2019-07-13 03:03发布

/*
 * =====================================================================================
 *
 *       Filename:  变量的存储布局.c
 *
 *    Description:   变量的存储布局
 *
 *        Version:  1.0
 *        Created:  2010年11月02日 10时48分07秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Yang Shao Kun (), cdutyangshaokun@163.com
 *        Company:  College of Information Engineering of CDUT
 *
 * =====================================================================================
 */
#include
const int A=10;
int a=20;
static int b=30;
int c;
int main(void)
{
    static int a=40;
    char b[]="hello world";
    register int c=50;
    printf("hello world %d/n",c);
    return 0;
}
49: 08049688     4 OBJECT  LOCAL  DEFAULT   24 b
50: 0804968c     4 OBJECT  LOCAL  DEFAULT   24 a.1697
65: 080484d4     4 OBJECT  GLOBAL DEFAULT   15 A
66: 08049684     4 OBJECT  GLOBAL DEFAULT   24 a
77: 08049698     4 OBJECT  GLOBAL DEFAULT   25 c


[13] .text             PROGBITS        08048310 000310 00019c 00  AX  0   0 16
[24] .data             PROGBITS        08049680 000680 000010 00  WA  0   0  4
[25] .bss              NOBITS          08049690 000690 00000c 00  WA  0   0  4
[15] .rodata           PROGBITS        080484c8 0004c8 000020 00   A  0   0  4


c语言的作用域:
scope:
    1:function scope (函数作用域),标识符在整个函数中都有效,只有标号是属于函数作用域
       的,标号在函数中不需要先申明后使用,在前面用一个goto语句也可以跳转到后面的某个标
       号,但是仅限与同一个函数之中,即使在函数内的某个语句快中定义一个标号,它也不局限
       与这个语句块,也是在整个函数中都有效。
    2:file scope--文件作用域,标识符在函数外申明,从它申明的位置开始直到这个源文件末尾
        都有效,我们上面的例子,中申明的标识符中,A,a,b,c 以及标识符main 都是文件作用域
        的,标识符printf 在stdio.h中申明后被包含到这个编译单元,此外,在函数外申明的类型
        明或tag也属于文件作用域。

        编译单元:--比如源文件a.x包含了b.h和c.h,那么经过预处理把b.h和c.h在a.c中张开后得
        到的代码称为一个编译单元,编译器将每个编译单元分别编译成一个目标文件,最后链接器
        把这些目标文件链接到一起成为一个可执行文件。
    3:块作用域(block scope),标识符在一对{}中申明,那么从它申明的位置开始到}之间是有
        效的。
    4:函数原型作用域 functon prototype scope  如果标识符出现在函数原型中,这个函数原型只
        是一个申明而不是定义(没有函数体),那么标识符从申明的位置到开始到这个原型结束之
        前有效。


对于同一命名的空间的重命名标识符:
    1:内层作用域的标识符将覆盖外层作用域的标识符,比如,局部变量名在它的函数中将覆盖重
    命名的全局变量
命名空间分为一下几类:
    2:语句标号单独属于一个空间命名空间,也就是说,函数局部变量和语句标号可以重名,互不影
    响,由于使用标号的语法和使用其他标识符的语法都不一样,编译器不会把它和别的标识符混淆
    3:struct enum,和 union  的tag属于一个命名空间,由于tag前面总是带 struct enum union
    关键字,所以编译器不会把它和别的标识符弄混淆。
    4:struct union 的成员名属于一个命名空间,由于成员名总是通过点运算符或->运算符来访问
    而不会单独使用,所以编译器也不会弄混淆。
    5:所有其他标识符,例如变量名,函数名,宏定义,typedef 定义的类型名,enum 成员等都属
    于同一个空间,会按照第一条来处理。
标识符的链接属性:
    1:外部链接,一个标识符在不同的编译单元中可能被申明多次,但这些编译单元链接成一个可
    执行文件时,如果这些申明都代表同一个变量或函数(即是代表同一个内存地址)
    2:内部链接,一个标识符在某个编译器单元中可能被申明多次。这些申明都代表同一个内存地
    址,但如果这个标识符在不同的编译单元中被申明多次,在链接的时候这些就不代表同一个内存
    地址。
    3:无链接属性。除了以上的情况,其他的都是属于这种情况。


    static  用它修饰的变量的储存空间是静态分配的,用它修饰的文件作用域的变量或函数具有
    内部链接
    auto:用它修饰的变量在函数调用时自动在栈上分配存储空间,函数返回时自动释放。
    register 编译器对用它来声明的变量会尽可能的分配一个专门的寄存器来存储,但是如果实在
    分配不开寄存器,编译器就把它但做auto变量处理了,它不能修饰文件作用域的变量。也就是声
    明的变量要在函数体的内部,不可能是全局的变量。
    extern: 用于多次声明具有链接属性的标识符。
    typedef :用来定义一个类型名。

变量的生存期:
    1:静态生存期,具有连接属性或者被static修饰的变量,在程序开始执行时分配内存和初始化
    之后一直存在直到程序结束
    2:自动生存期,无链接属性并且没有被 static 修饰的变量。
    3:动态分配生存期,它是在某个函数中调用malloc分配的,需要调用free函数来释放。