首页 > 代码库 > static关键字以及字符串常量的理解

static关键字以及字符串常量的理解

一、作用域、链接属性以及存储类型:

1.      作用域:常见作用域有代码块、文件、函数以及原型作用域(只适用于在函数原型中声明的参数名)。

2.      链接属性:

     a)        链接可以将多个目标文件链接生成最后的目标文件。链接属性则是决定如何处理在不同文件中出现的标识符

     b)        链接属性总共有三种:external(外部)、internal(内部)以及none(无)。默认情况下标识符一般是外部或者无属性,但是,通过static关键字,则可以改变标识符的属性,将外部属性转变成内部属性,一般我们所说的内外链接属性其实也是相对于文件作用域而言的。


                  默认情况下,上图中b,c,f的链接属性是外部的,其它的则是无链接属性,f是一个外部函数,

                 【补充】extern关键字则可以指定某个标识符是来自于外部源文件,即可以将原来的内部或者无链接属性改成外部链接属性。我们可以考虑一种比较复杂的情况,那就是当内外链接属性作用域同一个标识符时,标识符的链接属性该如何取舍?

          

                        如上图,extern关键字作用于标识符i并试图改变其链接属性时,此时会失效,即它不会更改前面已有的链接属性

    c)        存储类型:

             i.   变量的存储类型是指存储变量值的内存类型,它觉得了变量何时创建、何时销毁以及它的值可以保存多久。大类上讲,有两个地方可以存储变量值:普通内存以及硬件寄存器。根据下面的内存划分图,可存储变量的区域主要有:静态区、堆区以及栈区

       【注意】存在静态区的变量主要是全局变量以及被static关键字转换的自动变量,值得注意的是,常量也是存放在静态区。我们可以特意分析下代码块内的自动变量被static修饰的情况:经过static修饰的自动变量,只是存储类型发生了变化,并不影响它的作用域,只能在代码内部访问。另外它在整个程序的执行过程中一直存在,并不会重新初始化

void count_test()
{
   static int count = 0;

   count++;

   printf("count is %d\n", count);
}

如上面这段代码,内置一个静态变量,可以统计函数被调用的次数。

      【扩展】被static修饰的自动变量的赋值问题:

        根据C99标准:All theexpressions in an initializer for an object that has static storage durationshall be constant expressions or string literals. 因此,对给利用static关键字改变存储属性的变量赋值时,一定只能是常量表达式或者字符串常量。否则会出现“initializer element is not constant”的编译错误。

     ii 寄存器变量          

      关键字register可以用于自动变量的声明,提示这个变量是存储在寄存器中,而不是内存中,对比内存,寄存器的变量访问效果更优。一般来讲,可以将使用频率最高的变量存在于寄存器中。


二、字符串常量:

         针对字符串常量,主要在于理解,如存储位置,以及一些高级用法。根据前面的存储类型可知,字符串常量的实质是一个指针常量,也应该是存储在静态区的。

char *TEST_pointer_constant()
{
    //stack
    char detailFaultStr[10] = {0}; //locao array is tmp and stored in stack.
  
    sprintf(detailFaultStr, "%s", "asd");
  
    //static data area
    char *detailFaultStr = "abc"; 


    return detailFaultStr;
}

int main(int argc, char **argv)
{
    char *tmp = TEST_pointer_constant();    
    printf("%s.\n", tmp);    
    return 0;
}

       上面这个例子从侧面反映了指针所指向的内存所存储的位置不同,而出现不同的结果,第一种情况返回的是一个数组名,其所指向的内存时存在栈中,其作用域只存在与整个函数中,而第二种情况则是指向的是静态区(字符串常量),它的作用域是整个程序运行期。另外通过这个例子,可以看出我们通常所理解的不能将函数内的局部变量作为返回值返回,也不是所有情况下都必须遵守。

         下面这个例子展示了常量表达式作为指针常量的灵活用法:

void TEST_pointer_constant()
{
    printf("%s.\n", "xyz"); //xyz
    printf("%s.\n", "xyz"+1); //yz
    printf("%c.\n", *"xyz"); //x
    printf("%c.\n", "xyz"[1]); //y
    printf("%c.\n", *("xyz"+2)); //z
    putchar("0123456789ABCDEF"[11%16]); //can use to convert hexadecimal  //B
}