簡體   English   中英

c 中的“如果”測試條件 - 它是否評估?

[英]'if' test condition in c - does it evaluate?

在 c 中的 if 語句的測試部分中調用 function 時,它的評估是否與您正常調用它一樣? 例如,除了返回值之外的所有影響都會評估並持續存在嗎?

例如,如果我想在調用 fseek 時包含錯誤檢查,我可以寫

if( fseek(file, 0, SEEK_END) ) {fprintf(stderr, "File too long")};

並且在功能上與以下內容相同:

long int i = fseek(file, 0, SEEK_END); 
if( i ) {fprintf(stderr, "File too long")};

?

https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#The-if-Statement

https://www.gnu.org/software/libc/manual/html_node/File-Positioning.html

是的,這完全一樣。 唯一的區別是您將無法再次使用 if 語句中執行的操作的結果。

在這兩種情況下,操作都是在條件(比較)發生之前執行的。 為了說明這一點,我們可以在機器代碼中看到兩種不同情況的結果。 請注意,output 機器碼會因操作系統和編譯器而異。

源文件'a.c':

#include <stdio.h>

int
main(void)
{
    FILE *f = fopen("testfile", "r");
    long int i = fseek(f, 0, SEEK_END);

    if (i)
        fprintf(stderr, "Error\n");
    return 0;
}

$ gcc -O1 a.c -oa

源文件'b.c':

#include <stdio.h>

int
main(void)
{
    FILE *f = fopen("testfile", "r");

    if (fseek(f, 0, SEEK_END))
        fprintf(stderr, "Error\n");
    return 0;
}

$ gcc -O1 b.c -ob

您會注意到,對於這兩種情況,我都使用了選項“-O1”,它允許編譯器引入小的優化,這主要是為了使機器代碼更簡潔,因為在沒有優化的情況下,編譯器會將“字面意思”轉換為機器代碼。

$ objdump -Mintel -D a |grep -i main -A20

0000000000001189 <main>:
    1189:   f3 0f 1e fa             endbr64 
    118d:   48 83 ec 08             sub    rsp,0x8
    1191:   48 8d 35 6c 0e 00 00    lea    rsi,[rip+0xe6c]        # 2004 <_IO_stdin_used+0x4>
    1198:   48 8d 3d 67 0e 00 00    lea    rdi,[rip+0xe67]        # 2006 <_IO_stdin_used+0x6>
    119f:   e8 dc fe ff ff          call   1080 <fopen@plt>

# Interesting part
    11a4:   48 89 c7                mov    rdi,rax # Sets return of fopen as param 1
    11a7:   ba 02 00 00 00          mov    edx,0x2 # Sets Ox2 (SEEK_END) as param 3
    11ac:   be 00 00 00 00          mov    esi,0x0 # Sets 0 as param 2
    11b1:   e8 ba fe ff ff          call   1070 <fseek@plt> # Call to FSEEK being made and stored in register
    11b6:   85 c0                   test   eax,eax # Comparison being made
    11b8:   75 0a                   jne    11c4 <main+0x3b> # Comparison jumping
# End of interesting part

    11ba:   b8 00 00 00 00          mov    eax,0x0
    11bf:   48 83 c4 08             add    rsp,0x8
    11c3:   c3                      ret    
    11c4:   48 8b 0d 55 2e 00 00    mov    rcx,QWORD PTR [rip+0x2e55]        # 4020 <stderr@@GLIBC_2.2.5>
    11cb:   ba 06 00 00 00          mov    edx,0x6
    11d0:   be 01 00 00 00          mov    esi,0x1
    11d5:   48 8d 3d 33 0e 00 00    lea    rdi,[rip+0xe33]        # 200f <_IO_stdin_used+0xf>
    11dc:   e8 af fe ff ff          call   1090 <fwrite@plt>
    11e1:   eb d7                   jmp    11ba <main+0x31>
    11e3:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
    11ea:   00 00 00 
    11ed:   0f 1f 00                nop    DWORD PTR [rax]

二進制“b”上的 Objdumping 產生幾乎相同的機器代碼結果。 總而言之,無論您在 if 語句中放入什么,都會對其進行評估,並且無論您是否先為其分配變量,都會產生一個幕后等效結果。

編輯:

作為參考,這是$ objdump -Mintel -D b |grep -i main -A20

0000000000001189 <main>:
    1189:   f3 0f 1e fa             endbr64 
    118d:   48 83 ec 08             sub    rsp,0x8
    1191:   48 8d 35 6c 0e 00 00    lea    rsi,[rip+0xe6c]        # 2004 <_IO_stdin_used+0x4>
    1198:   48 8d 3d 67 0e 00 00    lea    rdi,[rip+0xe67]        # 2006 <_IO_stdin_used+0x6>
    119f:   e8 dc fe ff ff          call   1080 <fopen@plt>

# Interesting Part
    11a4:   48 89 c7                mov    rdi,rax
    11a7:   ba 02 00 00 00          mov    edx,0x2
    11ac:   be 00 00 00 00          mov    esi,0x0
    11b1:   e8 ba fe ff ff          call   1070 <fseek@plt>
    11b6:   85 c0                   test   eax,eax
    11b8:   75 0a                   jne    11c4 <main+0x3b>
# End of interesting part

    11ba:   b8 00 00 00 00          mov    eax,0x0
    11bf:   48 83 c4 08             add    rsp,0x8
    11c3:   c3                      ret    
    11c4:   48 8b 0d 55 2e 00 00    mov    rcx,QWORD PTR [rip+0x2e55]        # 4020 <stderr@@GLIBC_2.2.5>
    11cb:   ba 06 00 00 00          mov    edx,0x6
    11d0:   be 01 00 00 00          mov    esi,0x1
    11d5:   48 8d 3d 33 0e 00 00    lea    rdi,[rip+0xe33]        # 200f <_IO_stdin_used+0xf>
    11dc:   e8 af fe ff ff          call   1090 <fwrite@plt>
    11e1:   eb d7                   jmp    11ba <main+0x31>
    11e3:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
    11ea:   00 00 00 
    11ed:   0f 1f 00                nop    DWORD PTR [rax]

簡短的回答是肯定的(就像你的小例子一樣),長的答案是可能的。

當邏輯表達式(任何)更復雜時,C 語言會對其進行評估,直到整個表達式的結果完全確定。 不評估剩余的操作。

例子:

int x = 0;

if(x && foo()) {} 

foo 不會被調用,因為x是假的 - 然后整個操作是假的。

int x = 1;

if(x && foo()) {} 

foo 將被調用,因為x為真,並且需要表達式的第二部分來獲得結果。

它被稱為短路評估,C 中的所有邏輯表達式都以這種方式評估。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM