';如果';c中的测试条件-是否进行评估?

';如果';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

当在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 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]