zoukankan      html  css  js  c++  java
  • 【C语言学习趣事】_GCC源代码分析_1_alloca.

      昨天晚上下载了一份GCC V1.42的代码,不知道是源代码本身有问题,还是下载的源代码有问题,看的第一个C文件就存在一些很

    奇怪的情况。

      首先要说的是: alloca.c 文件的作用,alloca.c文件的函数实现动态堆空间的分配,即运行时堆栈空间分配。

    【1】源代码

      1 /*
      2     alloca -- (mostly) portable public-domain implementation -- D A Gwyn
      3 
      4     last edit:    86/05/30    rms
      5        include config.h, since on VMS it renames some symbols.
      6        Use xmalloc instead of malloc.
      7 
      8     This implementation of the PWB library alloca() function,
      9     which is used to allocate space off the run-time stack so
     10     that it is automatically reclaimed upon procedure exit, 
     11     was inspired by discussions with J. Q. Johnson of Cornell.
     12 
     13     It should work under any C implementation that uses an
     14     actual procedure stack (as opposed to a linked list of
     15     frames).  There are some preprocessor constants that can
     16     be defined when compiling for your specific system, for
     17     improved efficiency; however, the defaults should be okay.
     18 
     19     The general concept of this implementation is to keep
     20     track of all alloca()-allocated blocks, and reclaim any
     21     that are found to be deeper in the stack than the current
     22     invocation.  This heuristic does not reclaim storage as
     23     soon as it becomes invalid, but it will do so eventually.
     24 
     25     As a special case, alloca(0) reclaims storage without
     26     allocating any.  It is a good idea to use alloca(0) in
     27     your main control loop, etc. to force garbage collection.
     28 */
     29 
     30 
     31 #ifndef lint
     32     static char    SCCSid[] = "@(#)alloca.c    1.1";    /* for the "what" utility */
     33 #endif
     34 
     35 #ifdef emacs
     36     #include "config.h"
     37     #ifdef static
     38 /* actually, only want this if static is defined as " "
     39    -- this is for usg, in which emacs must undefine static
     40    in order to make unexec workable
     41    */
     42         #ifndef STACK_DIRECTION
     43             you
     44             lose
     45             -- must know STACK_DIRECTION at compile-time
     46         #endif /* STACK_DIRECTION undefined */
     47     #endif static 
     48 #endif emacs
     49 
     50 
     51 //很显然这里是对 X3J11 规范的定义
     52 #ifdef X3J11
     53     typedef void    *pointer;        /* generic pointer type */
     54 #else
     55     typedef char    *pointer;        /* generic pointer type */
     56 #endif
     57 
     58 //为什么这个地方不定义为 (void*)
     59 #define    NULL    0            /* null pointer constant */
     60 
     61 extern void    free();
     62 extern pointer    xmalloc();
     63 
     64 /*
     65     Define STACK_DIRECTION if you know the direction of stack
     66     growth for your system; otherwise it will be automatically
     67     deduced at run-time.
     68 
     69     STACK_DIRECTION > 0 => grows toward higher addresses
     70     STACK_DIRECTION < 0 => grows toward lower addresses
     71     STACK_DIRECTION = 0 => direction of growth unknown
     72 */
     73 
     74 
     75 //查看是否定义了栈增长方向宏定义
     76 #ifndef STACK_DIRECTION
     77     #define    STACK_DIRECTION    0        /* direction unknown */
     78 #endif
     79 
     80 //定义栈空间的增长方向宏 STACK_DIR
     81 #if  STACK_DIRECTION != 0
     82     #define    STACK_DIR    STACK_DIRECTION    /* known at compile-time */
     83 #else    /* STACK_DIRECTION == 0; need run-time code */
     84     static int    stack_dir;        /* 1 or -1 once known */
     85     #define    STACK_DIR    stack_dir
     86     //下面的函数用来判断栈的增长方向
     87     static void      
     88     find_stack_direction (/* void */)
     89     {
     90           static char    *addr = NULL;     /* address of first `dummy', once known */
     91           auto char    dummy;        /* to get stack address */
     92 
     93           if (addr == NULL)
     94             {                /* initial entry */
     95               addr = &dummy;
     96                find_stack_direction ();    /* recurse once */
     97          }
     98           else                /* second entry */
     99               if (&dummy > addr)
    100                   stack_dir = 1;        /* stack grew upward */
    101                else
    102                  stack_dir = -1;        /* stack grew downward */
    103     }
    104 #endif    /* STACK_DIRECTION == 0 */
    105 
    106 
    107 /*
    108     An "alloca header" is used to:
    109     (a) chain together all alloca()ed blocks;
    110     (b) keep track of stack depth.
    111 
    112     It is very important that sizeof(header) agree with malloc()
    113     alignment chunk size.  The following default should work okay.
    114 */
    115 
    116 #ifndef    ALIGN_SIZE
    117     #define    ALIGN_SIZE    sizeof(double)
    118 #endif 
    119 
    120 typedef union hdr
    121 {
    122      char    align[ALIGN_SIZE];    /* to force sizeof(header) */
    123      struct
    124        {
    125            union hdr *next;        /* for chaining headers */
    126         char *deep;        /* for stack depth measure */
    127      } h;
    128 } header;
    129 
    130 /*
    131     alloca( size ) returns a pointer to at least `size' bytes of
    132     storage which will be automatically reclaimed upon exit from
    133     the procedure that called alloca().  Originally, this space
    134     was supposed to be taken from the current stack frame of the
    135     caller, but that method cannot be made to work for some
    136     implementations of C, for example under Gould's UTX/32.
    137 */
    138 
    139 //全局变量用来存储 栈 指针
    140 static header *last_alloca_header = NULL; /* -> last alloca header */
    141 
    142 //动态堆分配函数, 这个函数有点类似 malloc 函数
    143 //但是这个函数具有垃圾回收机制
    144 pointer
    145 alloca (size)            /* returns pointer to storage */
    146      unsigned    size;        /* # bytes to allocate */
    147 {
    148   auto char    probe;        /* probes stack depth: */
    149   register char    *depth = &probe;
    150 
    151 #if  STACK_DIRECTION == 0
    152       if (STACK_DIR == 0)        /* unknown growth direction */
    153             find_stack_direction ();
    154 #endif
    155 
    156 /* Reclaim garbage, defined as all alloca()ed storage that
    157 was allocated from deeper in the stack than currently. */
    158   {
    159     register header    *hp;    /* traverses linked list */
    160 
    161       //可以发现这里for循环的语法非常特殊
    162     for (hp = last_alloca_header; hp != NULL;)
    163       if (STACK_DIR > 0 && hp->h.deep > depth || STACK_DIR < 0 && hp->h.deep < depth)
    164       {
    165          register header *np = hp->h.next;
    166          free ((pointer) hp);    /* collect garbage */
    167          hp = np;        /* -> next header */
    168       }
    169       else
    170         break;            /* rest are not deeper */
    171 
    172     last_alloca_header = hp;    /* -> last valid storage */
    173   }
    174 
    175   if (size == 0)
    176     return NULL;        /* no allocation required */
    177 
    178   /* Allocate combined header + user data storage. */
    179   {
    180     register pointer new = xmalloc (sizeof (header) + size);
    181     /* address of header */
    182 
    183     ((header *)new)->h.next = last_alloca_header;
    184     ((header *)new)->h.deep = depth;
    185 
    186     last_alloca_header = (header *)new;
    187 
    188     /* User storage begins just after header. */
    189     return (pointer)((char *)new + sizeof(header));
    190    }
    191 
    192   }
    View Code

    【2】第一个预处理

    #ifndef lint
        static char    SCCSid[] = "@(#)alloca.c    1.1";    /* for the "what" utility */
    #endif

      这个语句的作用就是定义一个描述源文件作用的数组,同时这个定义在V1.42中是一定定义的;通过代码分析工具查看交叉索引可以知道:

    ---- lint Matches (4 in 2 files) ----
    Alloca.c (g:\15_gcc\gcc_v1_42\gcc-1.42):#ifndef lint
    Va-mips.h (g:\15_gcc\gcc_v1_42\gcc-1.42):#ifdef lint    /* complains about constant in conditional context */
    Va-mips.h (g:\15_gcc\gcc_v1_42\gcc-1.42):#else        /* !lint */
    Va-mips.h (g:\15_gcc\gcc_v1_42\gcc-1.42):#endif        /* lint */

      可以发现在V1.42中并没有定义这个宏符号:lint

      因此可以确定,SCCSid数组必定定义,而且具有文件内可引用属性。

    【3】第二个预处理

    #ifdef emacs
        #include "config.h"
        #ifdef static
    /* actually, only want this if static is defined as " "
       -- this is for usg, in which emacs must undefine static
       in order to make unexec workable
       */
            #ifndef STACK_DIRECTION
                you
                lose
                -- must know STACK_DIRECTION at compile-time
            #endif /* STACK_DIRECTION undefined */
        #endif static 
    #endif emacs

      同样,在V1.42中并没有emacs宏符号的定义,因此这个预处理语句是不会被解释的

    【4】第三个预处理

    //很显然这里是对 X3J11 规范的定义判断
    #ifdef X3J11
        typedef void    *pointer;        /* generic pointer type */
    #else
        typedef char    *pointer;        /* generic pointer type */
    #endif

      同样在V1.42中并没有定义X3J11宏符号,因此 这里定义一个新的数据类型pointer, 其实质数据类型为 char* 

      这里用X3J11表示的是ANSI C标准。

    【5】定义宏,和声明外部符号

    //为什么这个地方不定义为 (void*)
    #define    NULL    0            /* null pointer constant */
    
    extern void    free();
    extern pointer    xmalloc();

      这里,xmalloc 函数相当于malloc函数,用来分配存储空间

    【6】判断系统栈空间增加方向

    //查看是否定义了栈增长方向宏定义
    #ifndef STACK_DIRECTION
        #define    STACK_DIRECTION    0        /* direction unknown */
    #endif
    
    //定义栈空间的增长方向宏 STACK_DIR
    #if  STACK_DIRECTION != 0
        #define    STACK_DIR    STACK_DIRECTION    /* known at compile-time */
    #else    /* STACK_DIRECTION == 0; need run-time code */
        static int    stack_dir;        /* 1 or -1 once known */
        #define    STACK_DIR    stack_dir
        //下面的函数用来判断栈的增长方向
        static void      
        find_stack_direction (/* void */)
        {
              static char    *addr = NULL;     /* address of first `dummy', once known */
              auto char    dummy;        /* to get stack address */
    
              if (addr == NULL)
                {                /* initial entry */
                  addr = &dummy;
                   find_stack_direction ();    /* recurse once */
             }
              else                /* second entry */
                  if (&dummy > addr)
                      stack_dir = 1;        /* stack grew upward */
                   else
                     stack_dir = -1;        /* stack grew downward */
        }
    #endif    /* STACK_DIRECTION == 0 */

      这里利用一个递归函数,find_stack_direction 来判断栈增长方向,是向高地址方向增长,还是地址方向增长。这里利用了一个static 

    local variable  addr 和一个 auto local variable dummy 来判断增长方向。

      思路比较巧妙。

      static:

        1、global 变量,则将变量作用域限制在单个源文件

        2、函数,则函数不能被定义函数源文件外的函数调用

        3、local 变量, 延长变量生命周期

    【7】堆 空间指针类型

    #ifndef    ALIGN_SIZE
        #define    ALIGN_SIZE    sizeof(double)
    #endif 
    
    typedef union hdr
    {
         char    align[ALIGN_SIZE];    /* to force sizeof(header) */
         struct
           {
               union hdr *next;        /* for chaining headers */
              char *deep;        /* for stack depth measure */
         } h;
    } header;

      定义了数据类型 header ,并且是用递归的联合体定义的, 联合体中定义成语域 align的目的是为了数据对齐;在下面的源代码中并没有

    对这个成员域的引用

    【8】堆 空间指针变量

    //全局变量用来存储 栈 指针
    static header *last_alloca_header = NULL; /* -> last alloca header */

      这里注释: last_alloca_header 用来指向最新分配的空间头(基指针)

    【9】alloca函数

     1 //动态堆分配函数, 这个函数有点类似 malloc 函数
     2 //但是这个函数具有垃圾回收机制
     3 pointer
     4 alloca (size)            /* returns pointer to storage */
     5      unsigned    size;        /* # bytes to allocate */
     6 {
     7   auto char    probe;        /* probes stack depth: */
     8   register char    *depth = &probe;
     9 
    10 #if  STACK_DIRECTION == 0
    11       if (STACK_DIR == 0)        /* unknown growth direction */
    12             find_stack_direction ();
    13 #endif
    14 
    15 /* Reclaim garbage, defined as all alloca()ed storage that
    16 was allocated from deeper in the stack than currently. */
    17   {
    18     register header    *hp;    /* traverses linked list */
    19 
    20       //可以发现这里for循环的语法非常特殊
    21     for (hp = last_alloca_header; hp != NULL;)
    22       if (STACK_DIR > 0 && hp->h.deep > depth || STACK_DIR < 0 && hp->h.deep < depth)
    23       {
    24          register header *np = hp->h.next;
    25          free ((pointer) hp);    /* collect garbage */
    26          hp = np;        /* -> next header */
    27       }
    28       else
    29         break;            /* rest are not deeper */
    30 
    31     last_alloca_header = hp;    /* -> last valid storage */
    32   }
    33 
    34   if (size == 0)
    35     return NULL;        /* no allocation required */
    36 
    37   /* Allocate combined header + user data storage. */
    38   {
    39     register pointer new = xmalloc (sizeof (header) + size);
    40     /* address of header */
    41 
    42     ((header *)new)->h.next = last_alloca_header;
    43     ((header *)new)->h.deep = depth;
    44 
    45     last_alloca_header = (header *)new;
    46 
    47     /* User storage begins just after header. */
    48     return (pointer)((char *)new + sizeof(header));
    49    }
    50 
    51   }
    View Code

    函数原型:

    pointer
    alloca (size)            /* returns pointer to storage */
         unsigned    size;    

      可以发现这里采用的老式的C语言函数定义形式,或者函数原型声明形式。

    局部变量:

    auto char    probe;        /* probes stack depth: */
    register char    *depth = &probe;

      局部变量用来检测堆栈的深度,

      register:

          1、声明为register的变量,表示要存储在CPU的寄存器中,提高存储效率。

    判断堆栈增长方向:

    #if  STACK_DIRECTION == 0
          if (STACK_DIR == 0)        /* unknown growth direction */
                find_stack_direction ();
    #endif

      增长结果存储在stack_dir全局变量中。

    回收内存:

    /* Reclaim garbage, defined as all alloca()ed storage that
    was allocated from deeper in the stack than currently. */
      {
        register header    *hp;    /* traverses linked list */
    
          //可以发现这里for循环的语法非常特殊
        for (hp = last_alloca_header; hp != NULL;)
          if (STACK_DIR > 0 && hp->h.deep > depth || STACK_DIR < 0 && hp->h.deep < depth)
          {
             register header *np = hp->h.next;
             free ((pointer) hp);    /* collect garbage */
             hp = np;        /* -> next header */
          }
          else
            break;            /* rest are not deeper */
    
        last_alloca_header = hp;    /* -> last valid storage */
      }

     分配空间

          如果申请的空间为0,则返回空指针。

    if (size == 0)
        return NULL;        /* no allocation required */

      如果申请的空间不为0 ,则返回申请空间的地址

     /* Allocate combined header + user data storage. */
      {
        register pointer new = xmalloc (sizeof (header) + size);
        /* address of header */
    
        ((header *)new)->h.next = last_alloca_header;
        ((header *)new)->h.deep = depth;
    
        last_alloca_header = (header *)new;
    
        /* User storage begins just after header. */
        return (pointer)((char *)new + sizeof(header));
       }
    
      }

    调用的主要函数:xmalloc的定义如下

    int
    xmalloc (size)
    {
      register int val = malloc (size);
    
      if (val == 0)
        fatal ("virtual memory exhausted");
      return val;
    }

      可以发现,这个函数还是调用的库函数malloc来实现的,但是这个函数有一个特点,其返回值是一个int类型的值,也就是说这个函数

    返回的可能是一个负值。

      反正我下载的这个代码库的源代码感觉是不对的,但是这里面一些思想和内容大体是对的,因此可以学习。 

    下面是我看到的bash 4.0 中关于这个函数alloca的源代码:

    /** alloca.c -- allocate automatically reclaimed memory
       (Mostly) portable public-domain implementation -- D A Gwyn
    
       This implementation of the PWB library alloca function,
       which is used to allocate space off the run-time stack so
       that it is automatically reclaimed upon procedure exit,
       was inspired by discussions with J. Q. Johnson of Cornell.
       J.Otto Tennant <jot@cray.com> contributed the Cray support.
    
       There are some preprocessor constants that can
       be defined when compiling for your specific system, for
       improved efficiency; however, the defaults should be okay.
    
       The general concept of this implementation is to keep
       track of all alloca-allocated blocks, and reclaim any
       that are found to be deeper in the stack than the current
       invocation.  This heuristic does not reclaim storage as
       soon as it becomes invalid, but it will do so eventually.
    
       As a special case, alloca(0) reclaims storage without
       allocating any.  It is a good idea to use alloca(0) in
       your main control loop, etc. to force garbage collection.  */
    
    #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    
    /** If compiling with GCC 2, this file's not needed.  */
    #if !defined (__GNUC__) || __GNUC__ < 2
    
    #include <bashtypes.h>        /** for size_t */
    
    /** If alloca is defined somewhere, this file is not needed. */
    #ifndef alloca
    
    #ifdef emacs
    #ifdef static
    /** actually, only want this if static is defined as ""
       -- this is for usg, in which emacs must undefine static
       in order to make unexec workable
       */
    #ifndef STACK_DIRECTION
    you
    lose
    -- must know STACK_DIRECTION at compile-time
    #endif /** STACK_DIRECTION undefined */
    #endif /** static */
    #endif /** emacs */
    
    /** If your stack is a linked list of frames, you have to
       provide an "address metric" ADDRESS_FUNCTION macro.  */
    
    #if defined (CRAY) && defined (CRAY_STACKSEG_END)
    long i00afunc ();
    #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
    #else
    #define ADDRESS_FUNCTION(arg) &(arg)
    #endif /** CRAY && CRAY_STACKSEG_END */
    
    #if __STDC__
    typedef void *pointer;
    #else
    typedef char *pointer;
    #endif
    
    #define    NULL    0
    
    /** Different portions of Emacs need to call different versions of
       malloc.  The Emacs executable needs alloca to call xmalloc, because
       ordinary malloc isn't protected from input signals.  On the other
       hand, the utilities in lib-src need alloca to call malloc; some of
       them are very simple, and don't have an xmalloc routine.
    
       Non-Emacs programs expect this to call use xmalloc.
    
       Callers below should use malloc.  */
    
    #ifndef emacs
    #define malloc xmalloc
    extern pointer xmalloc ();
    #endif
    
    /** Define STACK_DIRECTION if you know the direction of stack
       growth for your system; otherwise it will be automatically
       deduced at run-time.
    
       STACK_DIRECTION > 0 => grows toward higher addresses
       STACK_DIRECTION < 0 => grows toward lower addresses
       STACK_DIRECTION = 0 => direction of growth unknown  */
    
    #ifndef STACK_DIRECTION
    #define    STACK_DIRECTION    0    /** Direction unknown.  */
    #endif
    
    #if STACK_DIRECTION != 0
    
    #define    STACK_DIR    STACK_DIRECTION    /** Known at compile-time.  */
    
    #else /** STACK_DIRECTION == 0; need run-time code.  */
    
    static int stack_dir;        /** 1 or -1 once known.  */
    #define    STACK_DIR    stack_dir
    
    static void
    find_stack_direction ()
    {
      static char *addr = NULL;    /** Address of first `dummy', once known.  */
      auto char dummy;        /** To get stack address.  */
    
      if (addr == NULL)
        {                /** Initial entry.  */
          addr = ADDRESS_FUNCTION (dummy);
    
          find_stack_direction ();    /** Recurse once.  */
        }
      else
        {
          /** Second entry.  */
          if (ADDRESS_FUNCTION (dummy) > addr)
        stack_dir = 1;        /** Stack grew upward.  */
          else
        stack_dir = -1;        /** Stack grew downward.  */
        }
    }
    
    #endif /** STACK_DIRECTION == 0 */
    
    /** An "alloca header" is used to:
       (a) chain together all alloca'ed blocks;
       (b) keep track of stack depth.
    
       It is very important that sizeof(header) agree with malloc
       alignment chunk size.  The following default should work okay.  */
    
    #ifndef    ALIGN_SIZE
    #define    ALIGN_SIZE    sizeof(double)
    #endif
    
    typedef union hdr
    {
      char align[ALIGN_SIZE];    /** To force sizeof(header).  */
      struct
        {
          union hdr *next;        /** For chaining headers.  */
          char *deep;        /** For stack depth measure.  */
        } h;
    } header;
    
    static header *last_alloca_header = NULL;    /** -> last alloca header.  */
    
    /** Return a pointer to at least SIZE bytes of storage,
       which will be automatically reclaimed upon exit from
       the procedure that called alloca.  Originally, this space
       was supposed to be taken from the current stack frame of the
       caller, but that method cannot be made to work for some
       implementations of C, for example under Gould's UTX/32.  */
    
    pointer
    alloca (size)
         size_t size;
    {
      auto char probe;        /** Probes stack depth: */
      register char *depth = ADDRESS_FUNCTION (probe);
    
    #if STACK_DIRECTION == 0
      if (STACK_DIR == 0)        /** Unknown growth direction.  */
        find_stack_direction ();
    #endif
    
      /** Reclaim garbage, defined as all alloca'd storage that
         was allocated from deeper in the stack than currently. */
    
      {
        register header *hp;    /** Traverses linked list.  */
    
        for (hp = last_alloca_header; hp != NULL;)
          if ((STACK_DIR > 0 && hp->h.deep > depth)
          || (STACK_DIR < 0 && hp->h.deep < depth))
        {
          register header *np = hp->h.next;
    
          free ((pointer) hp);    /** Collect garbage.  */
    
          hp = np;        /** -> next header.  */
        }
          else
        break;            /** Rest are not deeper.  */
    
        last_alloca_header = hp;    /** -> last valid storage.  */
      }
    
      if (size == 0)
        return NULL;        /** No allocation required.  */
    
      /** Allocate combined header + user data storage.  */
    
      {
        register pointer new = malloc (sizeof (header) + size);
        /** Address of header.  */
    
        ((header *) new)->h.next = last_alloca_header;
        ((header *) new)->h.deep = depth;
    
        last_alloca_header = (header *) new;
    
        /** User storage begins just after header.  */
    
        return (pointer) ((char *) new + sizeof (header));
      }
    }
    
    #if defined (CRAY) && defined (CRAY_STACKSEG_END)
    
    #ifdef DEBUG_I00AFUNC
    #include <stdio.h>
    #endif
    
    #ifndef CRAY_STACK
    #define CRAY_STACK
    #ifndef CRAY2
    /** Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
    struct stack_control_header
      {
        long shgrow:32;        /** Number of times stack has grown.  */
        long shaseg:32;        /** Size of increments to stack.  */
        long shhwm:32;        /** High water mark of stack.  */
        long shsize:32;        /** Current size of stack (all segments).  */
      };
    
    /** The stack segment linkage control information occurs at
       the high-address end of a stack segment.  (The stack
       grows from low addresses to high addresses.)  The initial
       part of the stack segment linkage control information is
       0200 (octal) words.  This provides for register storage
       for the routine which overflows the stack.  */
    
    struct stack_segment_linkage
      {
        long ss[0200];        /** 0200 overflow words.  */
        long sssize:32;        /** Number of words in this segment.  */
        long ssbase:32;        /** Offset to stack base.  */
        long:32;
        long sspseg:32;        /** Offset to linkage control of previous
                       segment of stack.  */
        long:32;
        long sstcpt:32;        /** Pointer to task common address block.  */
        long sscsnm;        /** Private control structure number for
                       microtasking.  */
        long ssusr1;        /** Reserved for user.  */
        long ssusr2;        /** Reserved for user.  */
        long sstpid;        /** Process ID for pid based multi-tasking.  */
        long ssgvup;        /** Pointer to multitasking thread giveup.  */
        long sscray[7];        /** Reserved for Cray Research.  */
        long ssa0;
        long ssa1;
        long ssa2;
        long ssa3;
        long ssa4;
        long ssa5;
        long ssa6;
        long ssa7;
        long sss0;
        long sss1;
        long sss2;
        long sss3;
        long sss4;
        long sss5;
        long sss6;
        long sss7;
      };
    
    #else /** CRAY2 */
    /** The following structure defines the vector of words
       returned by the STKSTAT library routine.  */
    struct stk_stat
      {
        long now;            /** Current total stack size.  */
        long maxc;            /** Amount of contiguous space which would
                       be required to satisfy the maximum
                       stack demand to date.  */
        long high_water;        /** Stack high-water mark.  */
        long overflows;        /** Number of stack overflow ($STKOFEN) calls.  */
        long hits;            /** Number of internal buffer hits.  */
        long extends;        /** Number of block extensions.  */
        long stko_mallocs;        /** Block allocations by $STKOFEN.  */
        long underflows;        /** Number of stack underflow calls ($STKRETN).  */
        long stko_free;        /** Number of deallocations by $STKRETN.  */
        long stkm_free;        /** Number of deallocations by $STKMRET.  */
        long segments;        /** Current number of stack segments.  */
        long maxs;            /** Maximum number of stack segments so far.  */
        long pad_size;        /** Stack pad size.  */
        long current_address;    /** Current stack segment address.  */
        long current_size;        /** Current stack segment size.  This
                       number is actually corrupted by STKSTAT to
                       include the fifteen word trailer area.  */
        long initial_address;    /** Address of initial segment.  */
        long initial_size;        /** Size of initial segment.  */
      };
    
    /** The following structure describes the data structure which trails
       any stack segment.  I think that the description in 'asdef' is
       out of date.  I only describe the parts that I am sure about.  */
    
    struct stk_trailer
      {
        long this_address;        /** Address of this block.  */
        long this_size;        /** Size of this block (does not include
                       this trailer).  */
        long unknown2;
        long unknown3;
        long link;            /** Address of trailer block of previous
                       segment.  */
        long unknown5;
        long unknown6;
        long unknown7;
        long unknown8;
        long unknown9;
        long unknown10;
        long unknown11;
        long unknown12;
        long unknown13;
        long unknown14;
      };
    
    #endif /** CRAY2 */
    #endif /** not CRAY_STACK */
    
    #ifdef CRAY2
    /** Determine a "stack measure" for an arbitrary ADDRESS.
       I doubt that "lint" will like this much. */
    
    static long
    i00afunc (long *address)
    {
      struct stk_stat status;
      struct stk_trailer *trailer;
      long *block, size;
      long result = 0;
    
      /** We want to iterate through all of the segments.  The first
         step is to get the stack status structure.  We could do this
         more quickly and more directly, perhaps, by referencing the
         $LM00 common block, but I know that this works.  */
    
      STKSTAT (&status);
    
      /** Set up the iteration.  */
    
      trailer = (struct stk_trailer *) (status.current_address
                        + status.current_size
                        - 15);
    
      /** There must be at least one stack segment.  Therefore it is
         a fatal error if "trailer" is null.  */
    
      if (trailer == 0)
        abort ();
    
      /** Discard segments that do not contain our argument address.  */
    
      while (trailer != 0)
        {
          block = (long *) trailer->this_address;
          size = trailer->this_size;
          if (block == 0 || size == 0)
        abort ();
          trailer = (struct stk_trailer *) trailer->link;
          if ((block <= address) && (address < (block + size)))
        break;
        }
    
      /** Set the result to the offset in this segment and add the sizes
         of all predecessor segments.  */
    
      result = address - block;
    
      if (trailer == 0)
        {
          return result;
        }
    
      do
        {
          if (trailer->this_size <= 0)
        abort ();
          result += trailer->this_size;
          trailer = (struct stk_trailer *) trailer->link;
        }
      while (trailer != 0);
    
      /** We are done.  Note that if you present a bogus address (one
         not in any segment), you will get a different number back, formed
         from subtracting the address of the first block.  This is probably
         not what you want.  */
    
      return (result);
    }
    
    #else /** not CRAY2 */
    /** Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
       Determine the number of the cell within the stack,
       given the address of the cell.  The purpose of this
       routine is to linearize, in some sense, stack addresses
       for alloca.  */
    
    static long
    i00afunc (long address)
    {
      long stkl = 0;
    
      long size, pseg, this_segment, stack;
      long result = 0;
    
      struct stack_segment_linkage *ssptr;
    
      /** Register B67 contains the address of the end of the
         current stack segment.  If you (as a subprogram) store
         your registers on the stack and find that you are past
         the contents of B67, you have overflowed the segment.
    
         B67 also points to the stack segment linkage control
         area, which is what we are really interested in.  */
    
      /** This might be _getb67() or GETB67 () or getb67 () */
      stkl = CRAY_STACKSEG_END ();
      ssptr = (struct stack_segment_linkage *) stkl;
    
      /** If one subtracts 'size' from the end of the segment,
         one has the address of the first word of the segment.
    
         If this is not the first segment, 'pseg' will be
         nonzero.  */
    
      pseg = ssptr->sspseg;
      size = ssptr->sssize;
    
      this_segment = stkl - size;
    
      /** It is possible that calling this routine itself caused
         a stack overflow.  Discard stack segments which do not
         contain the target address.  */
    
      while (!(this_segment <= address && address <= stkl))
        {
    #ifdef DEBUG_I00AFUNC
          fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
    #endif
          if (pseg == 0)
        break;
          stkl = stkl - pseg;
          ssptr = (struct stack_segment_linkage *) stkl;
          size = ssptr->sssize;
          pseg = ssptr->sspseg;
          this_segment = stkl - size;
        }
    
      result = address - this_segment;
    
      /** If you subtract pseg from the current end of the stack,
         you get the address of the previous stack segment's end.
         This seems a little convoluted to me, but I'll bet you save
         a cycle somewhere.  */
    
      while (pseg != 0)
        {
    #ifdef DEBUG_I00AFUNC
          fprintf (stderr, "%011o %011o\n", pseg, size);
    #endif
          stkl = stkl - pseg;
          ssptr = (struct stack_segment_linkage *) stkl;
          size = ssptr->sssize;
          pseg = ssptr->sspseg;
          result += size;
        }
      return (result);
    }
    
    #endif /** not CRAY2 */
    #endif /** CRAY && CRAY_STACKSEG_END */
    
    #endif /** no alloca */
    #endif /** !__GNUC__ || __GNUC__ < 2 */
    View Code

      可以发现两个的写法还是有很多的区别。

  • 相关阅读:
    Oracle 11g服务详细介绍及哪些服务是必须开启的?
    分析函数Ratio_to_report使用
    在datagrid中,IE浏览器报错:SCRIPT5007: 无法获取属性“rowspan”的值: 对象为 null 或未定义
    身为一个产品经理应该了解自己的本职
    创意思维常用练习方法资料
    思维导图五个关键秘诀
    思维导图与超级记忆力之间的联系
    易让大脑变迟钝的九中习惯
    分享怎样快速阅读的5大方法
    思维导图运用的四个特征
  • 原文地址:https://www.cnblogs.com/volcanol/p/3098048.html
Copyright © 2011-2022 走看看