简体   繁体   English

c 中的“如果”测试条件 - 它是否评估?

[英]'if' test condition in c - does it evaluate?

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?在 c 中的 if 语句的测试部分中调用 function 时,它的评估是否与您正常调用它一样? 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例如,如果我想在调用 fseek 时包含错误检查,我可以写

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/gnu-c-manual/gnu-c-manual.html#The-if-Statement

https://www.gnu.org/software/libc/manual/html_node/File-Positioning.html 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.唯一的区别是您将无法再次使用 if 语句中执行的操作的结果。

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.请注意,output 机器码会因操作系统和编译器而异。

Source file 'a.c':源文件'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':源文件'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.您会注意到,对于这两种情况,我都使用了选项“-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]

Objdumping on binary 'b' yields an almost identical same machine code result.二进制“b”上的 Objdumping 产生几乎相同的机器代码结果。 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.总而言之,无论您在 if 语句中放入什么,都会对其进行评估,并且无论您是否先为其分配变量,都会产生一个幕后等效结果。

Edit:编辑:

For reference, this is the output of $ objdump -Mintel -D b |grep -i main -A20 :作为参考,这是$ 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.当逻辑表达式(任何)更复杂时,C 语言会对其进行评估,直到整个表达式的结果完全确定。 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. foo 不会被调用,因为x是假的 - 然后整个操作是假的。

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. foo 将被调用,因为x为真,并且需要表达式的第二部分来获得结果。

It is called Short circuit evaluation and all logical expressions in C are evaluated this way.它被称为短路评估,C 中的所有逻辑表达式都以这种方式评估。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM