精华内容
下载资源
问答
  • 变量名和符号表

    千次阅读 2015-07-26 02:16:17
    变量名是给编译器看的,编译器根据变量局部还是全局分配内存地址或栈空间,所谓的变量名在内存中存在,操作时转换成地址数存放在寄存器中了。其实可以理解为是符号表起到了连接作用。 (二)符号表 ...
    (一)变量名
    
    变量名是给编译器看的,编译器根据变量是局部还是全局分配内存地址或栈空间,所谓的变量名在内存中不存在,操作时转换成地址数存放在寄存器中了。其实可以理解为是符号表起到了连接作用。

    (二)符号表

     在编译程序中,符号表是用来存放源程序中出现的有关名字的属性信息,这些信息集中反映了名字的语义特征属性。符号表在编译全过程的地位和作用非常重要,是进行上下文合法性检查和语义处理及代码生成的依据。符号表总体结构的设计和实现是与源语言的复杂性(包括词法结构、语法结构的复杂性)有关,还与对于编译系统在时间效率和空间效率方面的要求有关。为此在本章中应对以下几个重点、难点问题作认真的学习,并切实掌握其中的内容。

    一、掌握符号的类型、存储类别和作用域及可视性的概念

    (1)符号的类型

        标识符中除过程标识符之外,函数和变量标识符都具有数据类型属性。对于函数的数据类型指的是该函数值的数据类型。基本数据类型有整型、实型、字符型、逻辑型(布尔型)及位组型等,符号的类型属性是在语言程序中该符号的定义中得到。变量符号的类型属性决定了该变量的数据在存储空间的存储格式,还决定了在该变量上可以施加的运算操作。

    (2)符号的存储类别

        多数语言对变量的存储类别定义采用二种方式。
        一种是用关键字指定。例如在C语言中,用Static定义是属于文件的静态存储变量或属于函数内部的静态存储变量,用regist定义使用寄存器存储的变量。
        另一种方式是根据定义变量说明在程序中的位置来决定。例如在C语言中,在函数体外缺省存储类关键字所定义的变量是外部变量,即程序的公共存储变量,而在函数体内缺省存储类关键字所定义的变量是内部变量,即属于该函数所独有的私有存储变量(通常是动态分配的存储变量,详细情况参阅存储空间的组织管理)。
        符号表中设置一个符号存储类别域,存放该符号的存储类别。区别符号存储类型的属性是编译过程语义处理、检查和存储分配的重要依据。符号的存储类别还决定了符号变量的作用域、可视性和它的生命周期等问题。

    (3)符号的作用域及可视性

        一个符号变量在程序中起作用的范围,称谓它的作用域。一般来说,定义该符号的位置及存储类关键字决定了该符号的作用域。例如,C语言中一个外部变量的作用域是整个程序,因此一个外部变量符号的定义在整个程序中只能出现一次,同名变量的说明可以出现多次那是为了使用和编译的方便。
        为确立符号的作用域和可视性。符号表属性中除了需要符号的存储类别之外还需要表示该符号在程序结构上被定义的层次。符号表中设置一个表达符号所在层次的属性域,存放该符号的定义层次。无论是作为函数形参的定义也好或作为分程序中的局部定义也好,都可统一地用定义层次来区分。一般来说,若把外部变量视为0层的话,则函数内部作为第1层,依次向内嵌套定义的分程序分别为2,3,…层。在C语言程序中函数之间是并列定义的,因此每个函数内部都定义为第一层,而函数内的分程序也可以是并列定义的,对于并列定义的分程序当然具有相同的层次号。

    二、掌握符号表总体组织的选择原则

        第一种:把属性种类完全相同的那些符号组织在一起,构造出表项是分别为等长的多个符号表。
        这样组织的最大优点是每个符号表的属性个数和结构完全相同。则表项是等长的,并且表项中的每个属性栏都是有效的,对于单个符号表示来说,这样使得管理方便一致,空间效率高。但这样组织的主要缺点是一个编译程序将同时管理若干个符号表,增加了总体管理的工作量和复杂度。而且对各类符号共同属性的管理必须设置重复的运行机制。使得符号表的管理显得臃肿。
        第二种:把所有语言中的符号都组织在一张符号表中。组成一张包括了所有属性的庞大的符号表。
        这样组织方式的最大优点是总体管理非常集中单一,且不同种类符号的共同属性可一致地管理和处理。这样组织所带来的缺点是,由于属性的不同,为完整表达各类符号的全部属性必将出现不等长的表项,以及表项中属性位置的交错重叠的复杂情况,这就极大地增加了符号表管理的复杂度。为使表项等长且实现属性位置的唯一性,可以把所有符号的可能属性作为符号表项属性。这种组织方法可能有助于降低符号表管理复杂性,但对某个具体符号,可能增加了无用的属性空间,从而增加了空间开销。
        第三种:折衷方式是根据符号属性相似程度分类组织成若干张表,每张表中记录的符号都有比较多的相同属性。这种折衷的组织方式在管理复杂性及时空效率方面都取得折衷的效果,并且对复杂性和效率的取舍可由设计者根据自己的经验和要求及目标系统的客观环境和需求进行选择和调整。

    三、掌握分程序结构的符号表组织

        对于具有分程序型结构的语言程序,不同层次分程序中定义的标识符号具有不同的作用域和不同的可视性规则。通常对于具有分程序结构的语言可用两种方式组织它们的符号表:一是对每个分程序建立一个独立的分表结构的符号表;一是把各分程序符号组织在一张单表结构的符号表中。例如,图9.1给出一个分程序结构的程序示例。 

    {//第一层分程序
     int a;
         float b,d;
                 {  //第二层分程序
          int c;
            float a;
                    { //第三层分程序
              int d;
                float c;
                        { //第四层分程序
                    float d;
                  ┊
                    a=b+c+d;
                  ┊
          }
     }
    }
    }

    图9.1  分程序结构的程序示例

    (1)分表结构
        分表结构的组织管理,其基本思想是每当编译程序扫描到一个分程序结构开始时,为该分程序建立一张符号表,在该分程序中定义的标识符,都被登录在该符号表中。而当编译程序扫描到一个分程序的结束时,编译程序释放为该分程序所建立的符号表。图9.2给出了与上述分程序结构的程序示例相应的分表结构组织。
        根据分程序作用域和可视规则,编译程序扫描到某个分程序时,符号的登录是在为该分程序所建立的符号表中进行,而符号的查找是首先在该分程序符号表中进行;若没有查到,再根据分程序的层次结构,逐层向外地依次查找各层符号表。一直到查到为止。若所有符号表都已查完仍未找到,则表示有词法错误。

    图9.2

    (2)单表结构

        单表结构的组织管理,其基本思想是所有分程序中定义的标识符都集中在单张符号表中。为了实现分程序构造中标识符的作用域和可视性规则的要求。在这种单表组织的符号表中,由于分层的分程序结构,因此需要强调三个主要的特定要求。
        首先,为了标志一个符号所属的分程序层次,在符号表中可设立一个属性域用来登录符号所在分程序的层次。
        其次,在编译程序扫描进入一个分程序时,表示分程序层次的状态量要增加一层,使进入分程序后定义的标识符登录符号表时,有相应的层次量作为层次属性登录。
        最后,对于具有分程序结构的源程序,在不同的分程序中(指嵌套的分程序中)允许定义重名的标识符。如果有重名标识符,可用下推链来组织。图9.3给出了与上述分程序结构的程序示例相应的单表结构组织。

    图9.3

    展开全文
  • SQL局部变量

    千次阅读 2017-02-24 16:16:31
    1.局部变量的定义: DECLARE 局部变量名 数据类型 【后面可以用逗号连接n个】 局部变量名必须是以@开头,要符合标识符的命名规则。 2.局部变量的赋值: 用SET或SELECT语句为局部变量赋值。 SET 局部变量名=表达式 ...

    1.局部变量的定义:

    DECLARE 局部变量名 数据类型 【后面可以用逗号连接n个】

    局部变量名必须是以@开头,要符合标识符的命名规则。


    2.局部变量的赋值:
    用SET或SELECT语句为局部变量赋值。

    SET 局部变量名=表达式

    SELECT 局部变量名=表达式 【后面可以用逗号连接n个


    3.变量值的输出,用PRINT或SELECT语句输出变量的值。

    PRINT 变量名

    SELECT 变量名 【后面可以用逗号连接n个

    PRINT只能一次输出一个变量,在“消息”窗口中显示,用SELECT可以同时输出多个变量,在“结果”子窗口中以表格形式显示。


    图片

    展开全文
  • static局部变量

    2018-03-28 10:33:11
    1.静态变量在内存的静态存储区,静态数据一直占有存储单元直到程序结束。2.静态局部变量只声明一次,一旦申请内存成功,不再接受...一般局部变量在函数调用结束后释放变量占用的存储单元,而静态局部变量不释放。...

    1.静态变量在内存的静态存储区,静态数据一直占有存储单元直到程序结束。

    2.静态局部变量只声明一次,一旦申请内存成功,不再接受重复申请。

    3.静态局部变量的作用域与一般局部变量一样,二者区别在于以上两点;一般局部变量在函数调用结束后释放变量占用的存储单元,而静态局部变量不释放。

    展开全文
  • 来源:公众号【编程珠玑】作者:守望先生前言这些是编程语言中的基本概念,如果你还不是非常明确地清楚标题的问题,并且知道作用域,链接属性,存储期等概念的具体含义,那么本文你...
        

    来源:公众号【编程珠玑】

    作者:守望先生

    前言

    这些是编程语言中的基本概念,如果你还不是非常明确地清楚标题的问题,并且不知道作用域,链接属性,存储期等概念的具体含义,那么本文你不该错过。为了更加清晰的理解我们的问题,需要先了解三个概念:作用域,链接属性,存储期。

    作用域

    C语言中,作用域用来描述标识符能够被哪些区域访问。

    而常见作用域有以下几种:

    为了便于说明,我们来看一个例子,就很容易理解了:

    /****************************作者:守望先生来源:公众号编程珠玑个人博客:https://www.yanbinghu.com***************************************/#include <stdio.h>int num1 = 222;         //定位在函数外,具有文件作用域static int num2 = 111;  //定义在函数外,具有文件作用域int swap(int *a,int *b); //这里的a,b是函数原型作用域int swap(int *a,int *b){    if(NULL== a || NULL == b)        goto error;        else    {        int temp = *a;  //定义在函数内,块作用域        *a = *b;        *b = temp;        return 0;    }    //printf("temp is %d\n",temp);   //因为temp具有块作用域,因此在这里不能直接使用    error://goto语句的标签,函数作用域,因此在前面就可以引用        {            printf("input para is NULL\n");            return -1;        }}int main(void){    printf("num1=%d,num2=%d\n",num1,num2);    swap(&num1,&num2);  //num1 num2具有文件作用域,可以在main函数中直接使用    printf("num1=%d,num2=%d",num1,num2);    return 0;}
    #include <stdio.h>
    int num1 = 222;         //定位在函数外,具有文件作用域
    static int num2 = 111;  //定义在函数外,具有文件作用域
    int swap(int *a,int *b)//这里的a,b是函数原型作用域
    int swap(int *a,int *b)
    {
        if(NULL== a || NULL == b)
            goto error;    
        else
        {
            int temp = *a;  //定义在函数内,块作用域
            *a = *b;
            *b = temp;
            return 0;
        }
        //printf("temp is %d\n",temp);   //因为temp具有块作用域,因此在这里不能直接使用
        error://goto语句的标签,函数作用域,因此在前面就可以引用
            {
                printf("input para is NULL\n");
                return -1;
            }
    }
    int main(void)
    {
        printf("num1=%d,num2=%d\n",num1,num2);
        swap(&num1,&num2);  //num1 num2具有文件作用域,可以在main函数中直接使用
        printf("num1=%d,num2=%d",num1,num2);
        return 0;
    }

    可以看到,error标签具有函数作用域,整个函数内都可见,而temp具有块作用域,因此在大括号外部,不能直接使用它。而num1和num2具有文件作用域,因此main函数可以直接使用它。

    链接属性

    在《hello程序是如何变成可执行文件的》我们说到了编译的过程,最后一个步骤就是链接。链接属性决定了在不同作用域的同名标识符能否绑定到同一个对象或者函数。或者说,不同作用域的标识符在编译后是否是同一个实体。

    c变量有三种链接属性:

    再稍作解释,没有static修饰,且具有文件作用域的变量,他们在链接时,多个同名标识符的变量最终都绑定到同一个实体。而static修饰的具有文件作用域的变量就不一样了,不同文件内,即便标识符名字相同,它们也绑定到了不同的实体。

    因此,如果我们希望某个变量或函数只在某一个文件使用,那么使用static修饰是一个很好的做法。

    同样的,来看一个例子。

    /****************************作者:守望先生来源:公众号编程珠玑个人博客:https://www.yanbinghu.com***************************************/#include <stdio.h>int a = 5;   //文件作用域,外部链接属性,其他文件可通过extern int a的方式使用该文件的astatic b = 6;  //文件作用域,内部链接属性,即便其他文件也有同名标识符,它们也是不同的int main(void){    int sum = 0 ; //无链接属性    sum = a + b;    printf("sum is %d\n",sum);    return 0;}
    #include <stdio.h>
    int a = 5;   //文件作用域,外部链接属性,其他文件可通过extern int a的方式使用该文件的a
    static b = 6;  //文件作用域,内部链接属性,即便其他文件也有同名标识符,它们也是不同的
    int main(void)
    {
        int sum = 0 ; //无链接属性
        sum = a + b;
        printf("sum is %d\n",sum);
        return 0;
    }

    从代码中可以看到,a和b都具有文件作用域,a具有外部链接属性,而b具有内部链接属性,sum具有块作用域,因此无链接属性。

    存储期

    实际上作用域和链接属性都描述了标识符的可见性,而存储期则描述了这些标识符对应的对象的生存期。存储期,也分下面几种:

    关于初始化,可参考《C语言入坑指南-被遗忘的初始化》。
    同样地,我们通过下面的代码来更好地理解存储期:

    /****************************作者:守望先生来源:公众号编程珠玑个人博客:https://www.yanbinghu.com***************************************/#include <stdio.h>int num1 = 222;         //静态存储期static int num2 = 111;  //静态存储期int add(int a,int b){    static int tempSum = 0;  //静态存储期    tempSum = tempSum + a + b;    return tempSum;}int main(void){    printf("num1=%d,num2=%d\n",num1,num2);    int sum = 0;  //自动存储期    sum = add(num1,num2);    printf("first time sum=%d\n",sum);//sum = 333    sum = add(num1,num2);    printf("second time sum=%d\n",sum); //sum = 666    return 0;}
    #include <stdio.h>
    int num1 = 222;         //静态存储期
    static int num2 = 111;  //静态存储期
    int add(int a,int b)
    {
        static int tempSum = 0;  //静态存储期
        tempSum = tempSum + a + b;
        return tempSum;
    }
    int main(void)
    {
        printf("num1=%d,num2=%d\n",num1,num2);
        int sum = 0;  //自动存储期
        sum = add(num1,num2);
        printf("first time sum=%d\n",sum);//sum = 333
        sum = add(num1,num2);
        printf("second time sum=%d\n",sum); //sum = 666
        return 0;
    }

    另外,如果我们通过nm命令查看编译出来的程序文件的符号表,我们可以找到num1,num2,tempSum,而没有sum,前者所用的内存数量在编译时就确定了。关于nm命令的使用可以参考《linux常用命令-开发调试篇》。

    $ gcc -g -o lifetime lifetime.c $ nm lifetime|grep num10000000000601038 D num1$ nm lifetime|grep num2000000000060103c d num2$ nm lifetime|grep tempSum0000000000601044 b tempSum.2289$ nm lifetime|grep sum$|grep num1
    0000000000601038 D num1
    $ nm lifetime|
    grep num2
    000000000060103c d num2
    $ nm lifetime|grep tempSum
    0000000000601044 b tempSum.2289
    $ nm lifetime|
    grep sum
    $

    什么全局变量,局部变量,静态局部变量,静态全局变量

    到这里,我们就可以很容易区分上面的变量类型了。实际上这里只是换了一种说法:
    全局:具有文件作用域的变量
    静态:具有静态存储期或内部链接属性
    局部:具有函数或块作用域的变量

    因而结合起来,也就很好理解了。

    当然,这仅仅是为了区分它们,这并不是它们的严格定义。更好的方法,是通过代码来理解:

    #include <stdio.h>int num1 = 222;         //全局变量static int num2 = 111;  //静态全局变量int add(int a,int b){    static int tempSum = 0;  //静态局部变量    tempSum = tempSum + a + b;    return tempSum;}int main(void){    printf("num1=%d,num2=%d\n",num1,num2);    int sum = 0;  //局部变量    sum = add(num1,num2);    printf("first time sum=%d\n",sum);//sum = 333    return 0;}
    int num1 = 222;         //全局变量
    static int num2 = 111;  //静态全局变量
    int add(int a,int b)
    {
        static int tempSum = 0;  //静态局部变量
        tempSum = tempSum + a + b;
        return tempSum;
    }
    int main(void)
    {
        printf("num1=%d,num2=%d\n",num1,num2);
        int sum = 0;  //局部变量
        sum = add(num1,num2);
        printf("first time sum=%d\n",sum);//sum = 333
        return 0;
    }

    总结

    本文总结如下:

    参考

    https://en.wikipedia.org/wiki/Global_variables

    https://en.wikipedia.org/wiki/Local_variable

    《C11标准文档》


    关注公众号【编程珠玑】,获取更多Linux/C/C++/Python/Go/算法/工具等原创技术文章。后台免费获取经典电子书和视频资源

    640?wx_fmt=jpeg

    展开全文
  • 今天被问到了一个问题:如何让请求的类延迟释放如果要延迟释放或者在程序整个生命周期都存在可以考虑两种方式,一是定义一个静态变量,二是用单例。用单例本质上用的是静态变量。单例的写法如下:+ (instancetype)...
  • 栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。 一个线程中方法的调用链可能会很长,很多方法都同时...
  • 全局变量与强符号和弱符号

    千次阅读 2016-10-18 15:29:06
    全局变量与强符号和弱符号
  • 局部变量和全局变量 $var1=6; echo "定义局部变量\$var=".$var1; include("a.php"); function myfun1(){ global $var1;//此处注意 echo "在myfun1()函数中输出局部变量"; echo "\$var1=".$var1; } ...
  • 全局变量和局部变量的区分

    千次阅读 热门讨论 2013-11-13 17:10:57
    全局变量,静态变量和局部变量的区别;从存储方式和作用域两个方面做了一个比较!
  • 变量名和内存地址及符号表

    千次阅读 2018-04-01 20:26:51
    1、变量名是给编译器看的,编译器根据变量局部还是全局分配内存地址或栈空间,所谓的变量名在内存中存在,操作时转换成地址数存放在寄存器中了。其实可以理解为是符号表起到了连接作用。 2、符号表 (此段...
  • 指针,是一个无符号整数(unsigned int),它是一个以当前系统寻址范围为取值范围的整数。 如:int* 是一个指针变量类型 指针变量和普通变量没有什么区别,指针32位四字节,里面保存的是一个内存空间的地址, 就...
  • 下面有几种网上的理解,我整理一下:一: 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员...
  • 局部变量和全局变量试题

    千次阅读 2011-03-28 08:47:00
    局部变量能否和全局变量重名?答:能,局部会屏蔽全局。要用全局变量,需要使用"::"局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一...
  •  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。  2、堆区(heap) — 一般由程序员分配释放, 若程序员释放,程序结束时可能由os回收 。...
  • 静态局部变量的说明

    千次阅读 2015-06-19 10:20:19
    对静态局部变量的说明:  (1) 静态局部变量在静态存储区内分配存储单元。在程序整个运行期间都释放。而自动变量(即动态局部变量)属于动态存储类别,存储在动态存储区空间(而不是静态存储区空间),函数调用结束...
  • 局部变量和全局变量的初始化

    千次阅读 2018-05-15 09:09:41
    因为这段内存空间在栈上,而栈内存是反复使用的(脏的,上次用完没清零的),所以说使用栈来实现的局部变量定义时如果显式初始化,值就是脏的。在C语言里,全局变量如果初始化的话,默认为0,也就是说在全局空间...
  • 关于 C++ 函数返回局部变量的警告

    千次阅读 2014-11-27 16:21:35
    关于 C++ 函数返回局部变量的警告 当函数返回时,局部变量和临时对象被销毁,所以返回的地址是无效的。需要修改代码,使其返回局部对象的地址。 那么如何解决?该怎么修改代码?
  • MySQL入门 SQL语言之十八:系统变量(全局变量、会话变量),自定义变量(用户变量、局部变量)的使用 #变量 /*系统变量: 全局变量  会话变量自定义变量: 用户变量  局部变量 */ #一、系统变量 /*说明:变量由...
  • 西门子S7-1200PLC局部变量相关知识

    千次阅读 2019-05-06 14:23:00
    什么是局部变量呢?在回答这个问题之前,有必要对变量声明有一个基本了解。在TIA Portal STEP7中有两种用来定义符号地址的表格形式:符号表(共享符号)和变量声明(局域符号),其本质都是为了建立绝对地址与...
  • ASM增加局部变量

    千次阅读 2015-03-10 20:33:04
    使用asm工具为一个函数添加局部变量后,重新加载该类失败。本篇文章主要分析错误的原因以及解决的办法。 首先了解一下虚拟机的类加载机制。类在初始化之前要完成加载、验证、准备和解析。 加载 加载过程分为三步: 1...
  • (1)栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。 (2)堆区(heap) — 由程序员分配和释放,若程序员释放,程序结束时可能由OS回收。 (3)全局区(静态区)(static)—,...
  • c中,一个文件里局部变量可以和全局变量重名。那这个文件编译出来的.o中,这两个变量的符号是怎么表示的呢?可能符号是相同的呀!c++处理这种情况时,符号表示和c一样还是不同呢?
  • vs2019 当前选中局部变量 颜色

    千次阅读 2019-08-30 15:02:21
    vs2019 当前选中局部变量 颜色 设置颜色:突出显示的定义、突出显示的引用。
  • 函数返回局部变量

    千次阅读 2011-10-28 21:52:24
    本文转自:...  关于局部变量的返回,准确的说应该是:能通过return 返回指向栈内存的指针!请看下面的两个例子: //----------------------------------------------------1[错误]-----------
  • 详细讲解全局变量和局部变量

    千次阅读 2020-10-27 19:50:48
    2、作用范围一样 局部变量:只有方法当中才可以使用,出了方法外就能使用; 成员变量:整个类中都可以使用; 3、默认值一样 局部变量:没有默认值,如果要想使用,必须手动赋值; 成员变量:如果没有赋值,会...
  • 返回局部变量的问题

    千次阅读 2011-05-15 23:07:00
    函数返回局部变量,是返回局部变量的值。但指针(或地址)是一种特殊的值,所以返回局部指针变量需要特别注意。正确情况下,作为函数返回值的局部指针,其所指向对象的作用域应该是调用者作用域、全局或静态常量区;...
  • 局部变量与全局变量  按照作用域不同将变量分为 局部变量和全局变量  局部变量:定义在函数内部变量  作用域:从定义的那一行开始直到所在代码结束  生命周期:从定义的那一行开始只直到其所在代码结束  ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 163,552
精华内容 65,420
关键字:

局部变量不入符号表