2014-02-16 71 views
1
int demo() 
{ 
    static int i = 1; 
    return i++; 
} 

int main() 
{ 
    printf("%d %d %d\n", demo(), demo(), demo()); 
    return 0; 
} 

輸出困惑: -關於return語句

3 2 1 

在第一demo呼叫,1返回。

我聽說當return語句被執行時,控制權轉移到calling函數,而不需要called函數的任何進一步執行代碼。

所以我的問題是,在我的代碼中,當第一次調用返回1時,爲什麼它的值增加了?

換句話說我想知道在返回1後,爲什麼++被執行?

+3

postfix ++返回舊*值*,*和*增量*變量*。不要混淆這兩個概念。增量是操作員的副作用。 – Elazar

+0

編譯此程序時,使用gcc的'-Wall'選項,它會向您顯示警告行爲可能未定義! – Nullpointer

+0

與[此問題]很相似(http://stackoverflow.com/questions/21808791/struct-vrs-classes-padding-templates)問了一會兒。 – devnull

回答

0

三點要記住這裏:

  1. static變量到功能,只要他們首次

  2. 該變量返回創建堅持通過程序的整個持續時間也有後綴 ++操作符,意思是:「使用該值(即返回它)並將其遞增」AFTERWARDS「:不會返回遞增的值。

這就是爲什麼該變量具有所發生的事情的「記憶」,並得到增加。

- >爲什麼你看到「3 2 1」而不是「1 2 3」?

其中參數進行評估是不知道「先天」,它是給編譯器的順序決定吧,看https://stackoverflow.com/a/12960263/1938163


如果你真的想知道它是如何可能的值被第一返回,然後遞增,看看所生成的彙編代碼:

demo():      # @demo() 
    movl demo()::i, %eax # move i and put it into eax 
    movl %eax, %ecx  # Move eax into ecx -> eax will be used/returned! 
    addl $1, %ecx  # Increment ecx 
    movl %ecx, demo()::i # save ecx into i -> this is for the next round! 
    ret      # returns! 

main:        # @main 
    pushq %rbp 
    movq %rsp, %rbp 
    subq $16, %rsp 
    movl $0, -4(%rbp) 
    callq demo()     # Call demo() 
    movl %eax, -8(%rbp)   # save eax in rbp-8 (contains 1, demo::i is 2 for the next round) 
    callq demo()     # Call demo() 
    movl %eax, -12(%rbp)   # save eax in rbp-12 (contains 2, demo::i is 3 for the next round) 
    callq demo()     # Call demo() 
    leaq .L.str, %rdi   # load str address 
    movl -8(%rbp), %esi   # esi points to 1 
    movl -12(%rbp), %edx   # edx points to 2 
    movl %eax, %ecx    # move eax (3) into ecx (demo::i is 4 but doesn't get used) 
    movb $0, %al     # needed by the ABI to call printf 
    callq printf     # call printf() and display 3 2 1 
    movl $0, %ecx 
    movl %eax, -16(%rbp)   
    movl %ecx, %eax 
    addq $16, %rsp 
    popq %rbp 
    ret 

demo()::i: 

.L.str: 
    .asciz "%d %d %d\n" 

64位ABI使用寄存器(RDI,RSI,RDX,RCX,R8和R9),而不是堆棧參數傳遞。

+0

請告訴我什麼'EAX'的意思? – zee

+0

eax是一個寄存器,一個足夠小的內存位置可以包含一個值或一個地址。它們不是變量,當你設置它時,它會一直存在,直到你再次改變它,所以在上面它用來移動靜態變量值。 –

0

你的函數返回舊值i並增加它。由於您使用了static關鍵字,因此i的值將被存儲並可用於下次呼叫(呼叫後它不會消失)。

我聽說當return語句被執行時,控制傳遞給調用函數,而不需要任何進一步執行調用函數中的代碼。

您聽說的權利。但這並不意味着return聲明返回的聲明不會執行。看一個例子:

return a + b; 

現在則執行該語句a+b得到評估,然後再它的值返回給調用者。

return i++; 

得到執行然後i++被執行。它返回前一個值i並將其增加1

1
int demo() 
{ 
    static int i = 1; 
    return i++; 
} 

int main() 
{ 
    printf("%d %d %d\n", demo1(), demo2(), demo3()); 
    return 0; 
} 

demo_i()的執行順序依賴於語言。

現在,使用static關鍵字。 Static variables堅持通過stack整個程序的持續時間,即使在function結束和returns的值。

Due to this , 1st time : i=1 
return 1 , increment to 2 . 
2nd time : i=2 
return 2 , increment to 3 . 
3rd time : i=3 
return 3 , increment to 4 . 

希望這有助於!

0

[...]我想知道,返回1後,爲什麼執行++?

後綴運算符是由C標準定義的這樣的工作:

6.5.2.4後綴增量和減量運算

[...]

2後綴++運算符的結果是操作數的值。在得到結果爲 後,操作數的值遞增。 (即,適當 類型的值1被添加到它。)

所以return之前執行i是增量,但作爲後綴操作的結果是「原始」的值,return返回這個「原始」值。