靜態變數與普通變數的區別

全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式, 靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。這兩者的區別雖在於非靜態全域性變數的作用域是整個源程式, 當一個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。 而靜態全域性變數則限制了其作用域, 即只在定義該變數的原始檔內有效, 在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於一個原始檔內,只能為該原始檔內的函式公用, 因此可以避免在其它原始檔中引起錯誤。

static全域性變數與普通的全域性變數
static全域性變數只初使化一次,作用域被限制在該變數的原始檔內有效,防止在其他檔案單元中被引用

static區域性變數和普通區域性變數
static區域性變數只被初始化一次,下一次依據上一次結果值

static函式與普通函式
static函式在記憶體中只有一份,普通函式在每個被呼叫中維持一份拷貝

static的初始化順序

先看個例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
    class B
    {
        public static int Y = A.X + 1;

        static B() { }

        static void Main(string[] args)
        {
            Console.WriteLine("X={0},Y={1}", A.X, B.Y);
            Console.Read();
        }
    }


    public class A
    {
        public static int X;
        static A()
        {
            X = B.Y + 1;
        }

    }
}

有圖有真相:


 執行結果是X=1,Y=2

 這個例子主要考查2個方面,一是static的用法,二是static的初始化順序。瞭解了static的初始化順序和規則,這個問題答答案就很容易理解了。這裡涉及到以下三類static物件:static成員,static方法,static建構函式。規則如下:

 一個類的static建構函式在給定的應用程式域中僅執行一次。static建構函式由在應用程式域的下列事件的首次發生時觸發:

 1)該類的例項被建立。

 2)任何一個static成員被引用

 3)如果類包含執行入口Main方法,此類的static建構函式在Main方法被呼叫之前執行。

 4)如果類包含任何staic成員,則這些static成員在static建構函式之前進行初始化。

 5)如果類包含任何static方法,則這些static方法在static建構函式之後進行初始化。

 6)對於存在多個static成員,他們的初始化將按照文字順序進行,不會因為呼叫順序而改變。

 現在看看上面的應用程式,Class B中有個Main執行入口,所以B首先得到初始化,順序是static成員Y->static建構函式。在初始化Y時,引用了A.X,編譯器又開始初始化Class A(注意這時Class B的初始化並沒有完成),順序也是static成員X->static建構函式。Class A中X在定義的時候沒有被賦予初始值(在定義static變數時,儘量賦予初始值),編譯器會預設賦予值0(int型)。然後再執行static的建構函式,由於Class B的初始化這時還沒有完成,所以B.Y的值在這時被編譯器賦予預設值0,所以在A的static的建構函式執行完後,X的值變為1,然後返回B繼續完成初始化,得到Y的值為2。最後執行Main,輸出A.X和B.Y的值。

=======================================================悲催的程式設計師==============================================================

1、static全域性變數與普通的全域性變數有什麼區別?static區域性變數和普通區域性變數有什麼區別?static函式與普通函式有什麼區別?
    答:全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。這兩者的區別雖在於非靜態全域性變數的作用域是整個源程式,當一個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。 而靜態全域性變數則限制了其作用域,即只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於一個原始檔內,只能為該原始檔內的函式公用,因此可以避免在其它原始檔中引起錯誤。
    從以上分析可以看出, 把區域性變數改變為靜態變數後是改變了它的儲存方式即改變了它的生存期。把全域性變數改變為靜態變數後是改變了它的作用域, 限制了它的使用範圍。
    static函式與普通函式作用域不同。僅在本檔案。只在當前原始檔中使用的函式應該說明為內部函式(static),內部函式應該在當前原始檔中說明和定義。對於可在當前原始檔以外使用的函式,應該在一個頭檔案中說明,要使用這些函式的原始檔要包含這個標頭檔案
    static全域性變數與普通的全域性變數有什麼區別:static全域性變數只初使化一次,防止在其他檔案單元中被引用;
    static區域性變數和普通區域性變數有什麼區別:static區域性變數只被初始化一次,下一次依據上一次結果值;
    static函式與普通函式有什麼區別:static函式在記憶體中只有一份,普通函式在每個被呼叫中維持一份拷貝

2.static有什麼用途?(請至少說明兩種)
    1)在函式體,一個被宣告為靜態的變數在這一函式被呼叫過程中維持其值不變。
    2) 在模組內(但在函式體外),一個被宣告為靜態的變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問。它是一個本地的全域性變數。
    3) 在模組內,一個被宣告為靜態的函式只可被這一模組內的其它函式呼叫。那就是,這個函式被限制在宣告它的模組的本地範圍內使用

=======================================================兩道騰訊筆試題============================================================

參考原文: