';如果';c中的测试条件-是否进行评估?
当在c中的if语句的测试部分调用函数时,它的计算结果是否与您正常调用它时完全相同?如中所示,除了返回值之外的所有效果是否都会评估并持续 例如,如果我想在调用fseek时包含一个错误检查,我可以写';如果';c中的测试条件-是否进行评估?,c,function,if-statement,fseek,C,Function,If Statement,Fseek,当在c中的if语句的测试部分调用函数时,它的计算结果是否与您正常调用它时完全相同?如中所示,除了返回值之外的所有效果是否都会评估并持续 例如,如果我想在调用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
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")};
?
简短的答案是肯定的(就像在你的小例子中一样),长的答案是可能的
当逻辑表达式(any)更复杂时,C语言将对其求值,直到完全确定整个表达式的结果。其余操作不进行评估
示例:
int x = 0;
if(x && foo()) {}
不会调用foo,因为x
为false-然后整个操作为false
int x = 1;
if(x && foo()) {}
将调用foo,因为x
为true,并且需要表达式的第二部分来获得结果
它被调用,C中的所有逻辑表达式都以这种方式计算。是的,这完全相同。唯一的区别是您将无法再次使用if语句中执行的操作的结果 在这两种情况下,操作都是在条件(比较)发生之前执行的。为了说明这一点,我们可以看到机器代码中两种不同情况的结果。请注意,输出机器代码会因操作系统和编译器的不同而不同 源文件“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;
}
#include <stdio.h>
int
main(void)
{
FILE *f = fopen("testfile", "r");
if (fseek(f, 0, SEEK_END))
fprintf(stderr, "Error\n");
return 0;
}
$gcc-o1b.c-ob
您会注意到,对于这两种情况,我都使用了选项'-O1',它允许编译器引入一些小的优化,这主要是为了使机器代码更干净,因为在没有优化的情况下,编译器会“逐字地”转换为机器代码
$objdump-Mintel-da | 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]
答案是肯定的。
它的评估结果是否与您正常调用的结果完全一致
答案是(很可能)是肯定的,我不确定我是否完全遵循了这个问题,即“完全一样”而不是什么/怎么做?@dxiv该问题解释道:“与中一样,返回值所包含的所有影响是否都会评估并持续存在?”.fseek
返回一个int
,而不是长int
。您所拥有的将起作用,但将int
返回值转换为long int
并没有实际意义。使用不同的类型也会产生误导。@user250102这完全不相关fseek
返回一个int
,它是0
或-1
。因此,您应该将i
声明为int
。对ftell
使用long
。对fseek
使用int
。这都是正确的,但在任何上下文中计算此类表达式时,都同样适用。作为if
测试条件的一部分,它没有什么特别或不同。@dxiv当逻辑表达式更复杂时,C语言会对其求值,直到整个表达式的结果完全确定为止
我是否只写了if
s?多糟糕的吹毛求疵啊。人们不读书,而是读书comment@P__J__你说“长答案是可能的。”考虑到问题“它的评估结果是否与你正常调用的结果完全一致”,人们可以轻松正确地将其解释为“可能条件的评估结果与你正常调用的结果完全一致。”它认为这是dxiv非常精明的一点。您的答案应该是,if
语句中的条件与任何其他表达式一样计算,句点。没有可能。您对短路评估的解释是有帮助的,但这并不是对条件的特别警告。@P_u_uj_u_u该问题是关于“如果测试条件”的特别说明。而且,你似乎认为否决票是我的。“不是。”P_uuj_uuu说得很对。事实上,如果条件,则根本不需要参考。我的观点是,你的答案是正确的,但与OP提出的问题不同。
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]