[英]'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.