When calling a function in the test portion of an if statement in c, does it evaluate exactly as if you had called it normally? As in, will all the effects besides the return value evaluate and persist?
For example, if I want to include an error check when calling fseek, can I write
if( fseek(file, 0, SEEK_END) ) {fprintf(stderr, "File too long")};
and be functionally the same as:
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
Yes, this is exactly the same. This only difference is you won't be able to use again the result of the operation executed in the if statement.
In both cases the operation is being executed BEFORE the condition (comparison) happens. To illustrate this, we can see what is the result of the two different cases in machine code. Please do note that the output machine code will vary depending of the OS and compiler.
Source file '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
Source file '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
You will note that for both cases I used the option '-O1' which allows the compiler to introduce small optimizations, this is mostly to make the machine code a little cleaner as without optimization the compiler converts "literally" to machine code.
$ 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]
Objdumping on binary 'b' yields an almost identical same machine code result. To sum it up, whatever you put in your if statement is evaluated and will yield a beind-the-scene equivalent result whether or not you assign it a variable first.
Edit:
For reference, this is the output of $ 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]
The short answer is yes (as in your trivial example), the long answer is maybe.
When the logical expression (any) is more complex the C language evaluates it until the result of the whole expression is fully determined. The remaining operations are not evaluated.
Examples:
int x = 0;
if(x && foo()) {}
the foo will not be called because x
is false - and then the whole operation is false.
int x = 1;
if(x && foo()) {}
the foo will be called because x
is true and the second part of the expression is needed to get the result.
It is called Short circuit evaluation and all logical expressions in C are evaluated this way.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.