2014-02-27 31 views
0

我有以下代碼c如何在不同的作用域上處理相同的變量名?

int main() 
{ 
     static int x = 8; 
     { 
       static int x = 9; 
     } 
     printf("%d",x); 
} 

O/P-8

我的疑問,按照規則說的靜態變量僅創建一次,並且在memory.So堅持如果與名稱X變量被持久化在內存中,那麼我怎麼能夠創建一個新的。

請清楚我的疑問。我經歷了谷歌,但它是如何完成的,我在C編程中想要什麼。編譯器如何標識變量以及它如何存儲在內存中。

T

+6

範圍。範圍。範圍。範圍... – devnull

+0

好的,但它是如何在內存中,區分兩個相同名稱的變量。 – pradipta

+0

爲什麼要爲此投票。我希望這只是我錯過的一個概念。 – pradipta

回答

1

靜態值將在函數調用期間持續存在。

但是在相同的功能範圍內獨自的問題。把一個printf支架裏面,你會明白

int main() 
{ 
     static int x = 8; 
     { 
       static int x = 9; 
       **printf("%d",x);** 
     } 
     printf("%d",x); 
} 
+0

那麼如果我將它定義在main.how上面呢? – pradipta

+0

如果將它定義在主體之上,就像全局變量一樣,但是由於它的靜態只在當前的.c文件中可見。 – tesseract

1

靜態變量創建一次,並在內存中持續了變量的範圍。

當您使用

{ 
    static int x = 9; 
    printf("%d",x) // would print 9 only 
} 

這將創建一個新的機會和x是來自設在大括號外面定義的x不同。

範圍可以與支架,函數來創建,文件

如果靜態變量在全局空間中聲明則是在整個文件持久。

但也記得局部範圍變量優先於具有相同名稱的全局變量。

2

objdump拆機輸出可爲您提供有關如何編譯器(gcc,在這種情況下)一些提示處理這種情況:

$ objdump -d a.out 
... 
000000000040050c <main>: 
    40050c: 55      push %rbp 
    40050d: 48 89 e5    mov %rsp,%rbp 
    400510: 8b 05 fa 03 20 00  mov 0x2003fa(%rip),%eax  # 600910 <x.2163> 
    400516: 89 c6     mov %eax,%esi 
    400518: bf fc 05 40 00   mov $0x4005fc,%edi 
    40051d: b8 00 00 00 00   mov $0x0,%eax 
    400522: e8 b9 fe ff ff   callq 4003e0 <[email protected]> 
    400527: 8b 05 e7 03 20 00  mov 0x2003e7(%rip),%eax  # 600914 <x.2162> 
    40052d: 89 c6     mov %eax,%esi 
    40052f: bf fc 05 40 00   mov $0x4005fc,%edi 
    400534: b8 00 00 00 00   mov $0x0,%eax 
    400539: e8 a2 fe ff ff   callq 4003e0 <[email protected]> 
    40053e: b8 00 00 00 00   mov $0x0,%eax 
    400543: 5d      pop %rbp 
    400544: c3      retq 

使用readelf,我們可以發現,每個x都有自己的符號最後的可執行文件:

$ readelf -s a.out 
... 
45: 0000000000600910  4 OBJECT LOCAL DEFAULT 25 x.2163 
46: 0000000000600914  4 OBJECT LOCAL DEFAULT 25 x.2162 

下面是C語言代碼:

int main() 
{ 
    static int x = 8; 
    { 
     static int x = 9; 
     printf("%d",x); 
    } 
    printf("%d",x); 
    return 0; 
} 
+0

你可以解釋一下這個裝配,我是新來的。 – pradipta

+0

@pradipta對不起,我無法真正理解那些彙編代碼。但很明顯,'gcc'給每個'x'一個不同的名字。 –

+0

感謝您的回答。 – pradipta

1

想象一下,每個開放{和關閉每個關閉}創建一個範圍。而且,對於每個新的作用域,變量的名稱都以範圍的名稱作爲前綴(精神上)(可以將其與名稱相關聯,或者對於您的示例中的匿名構造, 「scope1」, 「scope2」, 「scope3」 序列

所以,基本上,有你定義兩個變量,而不是一個:

靜態INT main.x = 8;

static int main.scope1。x = 9;

這兩個都是靜態的,但它們(對於編譯器和程序的邏輯)具有不同的名稱,並且像不同的變量一樣起作用。只有他們縮寫的名字是相同的,「x」,這是讓你感到困惑的,但這些變量實際上是不同的。他們尊重你所說的「靜態」,但沒有衝突。

警告一句話:在「scope1」內部,變量「main.scope1.x」隱藏變量「main.x」。

請記住,使用範圍名稱進行這種「重命名」僅僅是一個類比,而不是真實的事情。不過,我希望這有助於理解這個問題。

1

理論編譯器可以保留遇到符號的堆棧。解析'{'時,編譯器可以將此分隔符放入堆棧,遇到'}'符號時,它將刪除最後一個'{'...'}'區域之間的所有符號。

當編譯器解析某個符號時,它可以深入研究符號堆棧以查找匹配或發現錯誤。

在解析該文件中的每個關鍵點,這個編譯器將具有象徵堆棧:

main main main main main  main main 
     {  {  {  {  { 
      x  x  x  x 
        {  { 
          x 

這種做法實際上相當密切映射到C編譯器的遺留實現 - 在X-ES會也被放置在現實中。

+0

感謝您的回答。 – pradipta

2

在內部,編譯器是重命名具有不同作用域的同義變量。 考慮您的文件:

// file pradipta.c 
#include <stdio.h> 
int main() { 
    static int x = 8; 
    { 
    static int x = 9; 
    } 
    printf ("%d\n", x); 
} 

然後用

gcc -fdump-tree-all -O -Wall pradipta.c -o pradipta.bin 

編譯它(在Linux上使用GCC),那麼你可以得到很多的pradipta.c.[0-9]*t.*文件。他們告訴你一個部分(因此不完整)轉儲GCC表示。一些內部變量可能不同,但名稱相同。在編譯器內部,一個變量在內部由一些複雜的數據結構表示(GCC說法中的一個tree節點,在gimple指令中使用),並且可以有兩個具有相同「可打印」名稱的不同結構。

你也可以使用MELT來探索GCC內部(或通過擴展GCC和你的MELT擴展來定製它的行爲)。

另請參見關於α-轉換λ-calculus

實際上,避免不同嵌套作用域的同義變量。它們使你的代碼非常難以被人讀取(即使編譯器給你的代碼提供了非常準確和明確的含義)。 -Wall選項要求提供所有警告,並且會針對這種情況發出警告。

+0

感謝您的明確答案。 – pradipta

相關問題