繁体   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