双&号在此程序中起什么作用?

发布于 2025-01-05 22:42:37 字数 462 浏览 1 评论 0原文

我正在学习如何使用 fork 创建进程,但我对以下内容感到困惑。代码如下:

int main() {
    int ret = fork();
    // printf("%d\n", ret);
    ret = ret && fork(); /* Here is where I am confused*/
    // print("ret: %d\n", ret);
    if(ret == 0) {
        fork();
    }
    printf("Hello world\n");
    return 1;
}

那么,双 & 符号到底有什么用呢? 我用“printf”运行程序来了解这些值到底是什么,但它变得更加混乱,因为第一个“printf”中的输出是 0,第二个“printf”中的输出是“1”。所以我不太确定双&符号在做什么。

我很感激你的帮助!

I am learning how to create processes by using fork, and I am confused in the following. This is the code:

int main() {
    int ret = fork();
    // printf("%d\n", ret);
    ret = ret && fork(); /* Here is where I am confused*/
    // print("ret: %d\n", ret);
    if(ret == 0) {
        fork();
    }
    printf("Hello world\n");
    return 1;
}

So, what is the use of double ampersand exactly doing?
I ran the program with a "printf" to know what was exactly the values, but it became more confusing because the output in the first "printf" is 0 and the second "printf" is "1". So I am not quite sure what is double ampersand doing.

I appreciate the help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

梦里的微风 2025-01-12 22:42:37

它称为逻辑 AND 运算符。这将评估两个操作数的逻辑与结果。该运算符的属性是:

首先计算左侧操作数,如果它为 TRUE(非零),则计算右侧操作数。如果它也为真,则整个表达式为真,否则为假。另一方面,如果左侧操作数为 FALSE,则右侧操作数根本不会被求值。之所以能做到这一点,是因为当其中一个操作数为假时,无论另一个操作数是什么,表达式都会变为假。这在您的代码中称为短路

,如果左手 if ret 是true,则仅计算右侧部分,最终调用 fork () 系统调用。调用的返回值与 ret 的当前值进行 AND 运算,并重新分配给 ret。

基本上它的工作原理

if (ret == TRUE)
{
  retval = fork ();
  ret = ret && retval;
}

如下:

成功时,在父进程中返回子进程的 PID,在子进程中返回 0。失败时,父进程返回 -1,不创建子进程,并适当设置 errno。

考虑下面的叉树。每个树“节点”显示每个单独语句中执行语句的顺序。一条线完成一项工作。

    (p1)
+--+ret = fork ();
|   printf 1 shows pid
|   && allows         fork (), ret = 1 = pid1 && pid2 
|   printf 2 shows 1    +
|   `if' not entered    |
|   show hello          |
|                       |    (p3)
|                       +--+ ret = 0 = ret && fork () (this is 0 here)
+-----+                      printf 2 shows 0
      |                      `if' is entered
      |                      fork ()
      |                      show hello
      |                            +
      |                            |
      +                            |
     (p2)                          |
    level 1                        +-------+
    print 0 in 1st printf                  |
    && DOES NOT allow fork ()            (p5)
    print 0 in 2st printf             show hello
   `if' entered
    fork () +-----------+
    show hello          |
                        |
                        +
                      (p4)
                    show hello

这是每个过程中发生的事情。

p1
执行fork()一次,并在ret中有一个pid(非零)。
打印pid
短路允许执行fork()。由于这是父级,它返回另一个 pid,该 pid 与前一个子 pid 进行“与”运算,结果为 1。因此 ret 现在包含 1,该值在第二个 printf 中打印。由于ret为1,if不执行。打印出“你好”。

p2
p1 的子级,因此 ret 为 0。在第一个 printf 中打印 0。短路不允许fork()调用。 if主体被输入,并且fork()被调用,这使得(p4)。现在 (p2) 继续打印 Hello。

p3
p1的孩子,所以fork()返回是0,与ret进行AND运算,赋值后变为0。这是在第一个 printf 之后生成的,因此只有第二个 printf 显示 0。
输入if,执行fork(),生成(p5)。现在 p4 继续打印 Hello。

p4
if 主体开始,退出并打印 Hello

p5
if 主体开始,退出并打印 Hello

上面我试图表达进程生成树,每个进程中的工作顺序由树上进程“节点”的每一行表示。边表示spawn,边从相应的分叉处开始。

It is called the logical AND operator. This will evaluate the logical ANDing result of the two operands. The property of this operator is:

First the left hand side operand is evaluated, if it is TRUE (non zero), then the right hand side operand is evaluated. If it is also true then the whole expression is true, or false otherwise. On the other hand, if the left hand side operand is FALSE, then the right hand side operand is not evaluated at all. This can be done because, as one of the operands is false, whatever be the other operand, the expression becomes false. This is known as short circuiting

In your code, if the left hand if ret is true, then only the right hand side portion is evaluated, which eventually calls the fork () system call. The return value of the call is ANDed with the current value of ret, and reassigned to ret.

Basically it works like

if (ret == TRUE)
{
  retval = fork ();
  ret = ret && retval;
}

Read this:

On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.

Consider the fork tree below. Each tree "node" shows the sequence of executed statement in each individual statement. One work in one line.

    (p1)
+--+ret = fork ();
|   printf 1 shows pid
|   && allows         fork (), ret = 1 = pid1 && pid2 
|   printf 2 shows 1    +
|   `if' not entered    |
|   show hello          |
|                       |    (p3)
|                       +--+ ret = 0 = ret && fork () (this is 0 here)
+-----+                      printf 2 shows 0
      |                      `if' is entered
      |                      fork ()
      |                      show hello
      |                            +
      |                            |
      +                            |
     (p2)                          |
    level 1                        +-------+
    print 0 in 1st printf                  |
    && DOES NOT allow fork ()            (p5)
    print 0 in 2st printf             show hello
   `if' entered
    fork () +-----------+
    show hello          |
                        |
                        +
                      (p4)
                    show hello

Here what goes in each process.

p1
executes fork () once, and has a pid (non-zero) in ret.
prints the pid
short circuit allows to execute fork (). As this is the parent, it returns another pid, which is anded with the previous child pid, which evaluates to 1. Therefore ret now contains 1, which is printed in the second printf. as ret is 1, if is not executes. Hello is printed.

p2
Child of p1, so ret has 0. prints 0 in the first printf. Short circuit does not allow fork () call. if body is entered, and fork () is called, which makes (p4). Now (p2) proceeds to print Hello.

p3
Child of p1, so fork () return is 0, which is ANDed with ret, and makes it 0 after the assignment. This is spawned after the first printf, so only the second printf shows 0.
if is entered, fork () is executed, which makes (p5). Now p4 proceeds to print Hello.

p4
starts from if body, gets out and prints Hello

p5
starts from if body, gets out and prints Hello

Above I have tried to express the process spawn tree, and the sequence of works in each process is expressed in each line of the process "node" on the tree. The edges denote spawn, and the edge start at the corresponding fork.

东北女汉子 2025-01-12 22:42:37

在 C 语言中,双与号 && 是短路逻辑 AND 运算。如果你有类似 a && b,则计算结果如下:如果 ab 都为 true,则返回 true,但如果 a 为 true,则返回 true false 则 b 将永远不会被执行。

作为添加的示例

int a = 0;
if (a && myfunc(b)) {
    do_something();
}

在此示例中,短路求值保证永远不会调用 myfunc(b)。这是因为 a 的计算结果为 false。此功能允许两种有用的编程结构。首先,如果第一个子表达式检查是否需要昂贵的计算并且检查结果为假,则可以消除第二个参数中的昂贵计算。其次,它允许第一个表达式保证一个条件,否则第二个表达式可能会导致运行时错误。

因此,如果 ret 为 true,您的代码仅调用 fork()。然后将 ret 指定为 0(ret 为 0)或 1(retfork() 均为 true )。

In C, the double ampersand && is a short-circuit logical AND operation. If you have something like a && b, then this will evaluate as follows: it will return true if both a and b are true, but if a is false then b will never be executed.

As an added example:

int a = 0;
if (a && myfunc(b)) {
    do_something();
}

In this example, short-circuit evaluation guarantees that myfunc(b) is never called. This is because a evaluates to false. This feature permits two useful programming constructs. Firstly, if the first sub-expression checks whether an expensive computation is needed and the check evaluates to false, one can eliminate expensive computation in the second argument. Secondly, it permits a construct where the first expression guarantees a condition without which the second expression may cause a run-time error.

So your code only calls fork() if ret is true. ret is then assigned either 0 (ret is 0) or 1 (both ret and fork() are true).

溺孤伤于心 2025-01-12 22:42:37

它是一个逻辑 AND,意味着如果 ret 为 true(非零),并且 fork() 的结果为 true(非零),则将 true 分配给 ret,否则将 false(零)分配给 ret

由于此运算符是短路fork()将仅当 ret 为 true 时才被调用。

It's a logical AND, meaning if ret is true (non-zero), AND the result of fork() is true (non-zero) assign true to ret, else assign false (zero) to ret.

Since this operator is short-cirucuited, fork() will be called only if ret is true.

一个人练习一个人 2025-01-12 22:42:37

我认为问题在于对 fork() 工作原理的误解。如果你使用的是 UNIX,你需要执行“man fork”,因为根据我读到的:

描述
fork() 通过复制调用进程来创建一个新进程。这
新进程(称为子进程)与
调用进程,称为父进程,

并且..

返回值
成功后,子进程的 PID 将返回到父进程中,并且
0 在子进程中返回。失败时,在父级中返回 -1,
没有创建子进程,并且正确设置了 errno。

我怀疑可能发生的情况是,您可能会看到多个分叉进程的输出,这只会让您感到困惑。您的程序的确切完整输出是什么?

这不太可能是短路问题,因为即使第二个失败,至少第一个 fork 应该成功,因此如果该 fork 成功,您应该从至少一个第一个 printfs 获得 pid。

I think what's wrong is a misunderstanding of how fork() works. If you're on UNIX, you need to do "man fork", because according to the one I read:

DESCRIPTION
fork() creates a new process by duplicating the calling process. The
new process, referred to as the child, is an exact duplicate of the
calling process, referred to as the parent,

and..

RETURN VALUE
On success, the PID of the child process is returned in the parent, and
0 is returned in the child. On failure, -1 is returned in the parent,
no child process is created, and errno is set appropriately.

I suspect what might be happening is you might be seeing output from multiple forked processes that is only succeeding in confusing you. What is the exact full output of your program?

This is unlikely to be a short circuit problem because even if the second one fails, at least the first fork should have succeeded, and thus you should get a pid from at least one of the first printfs if that fork succeeded.

不疑不惑不回忆 2025-01-12 22:42:37

这是一个惰性逻辑 AND 函数。如果您需要更多信息,请搜索 AND 的真值表。它是惰性的,因为如果 ret 为 false,则不会评估 fork(),因为与 false 进行 AND 运算的任何内容始终为 false

It's a lazy logical AND function. Search for the truth table for AND if you need more info on that. It's lazy because if ret is false, fork() will not be evaluated since anything ANDed with false is always false.

兮颜 2025-01-12 22:42:37

这是一个短路逻辑与。如果ret为0,那么它将执行fork()。如果没有,就不会。我可以为您演示一下代码。

//we fork a child process
int ret = fork();

//ret is 0 if we are in the child process, -1 if fork failed
//otherwise ret is the process id of the child process

//because of this, the fork below executes only within the child process
ret = ret && fork(); /* Here is where I am confused*/

//at this point, if we did fork a process (in the child), then ret is 0 in the child
//then we fork again
if(ret == 0) {
    fork();
}

所以我们有第一个进程,进程 1 执行此代码。让我们假设所有分叉都成功(但您应该确保检查这一点...我认为它应该在现有代码中处理,但并不那么明显)。

  • 进程 1 分叉,创建一个进程 ID 为 2 的子进程。
  • 现在,进程 1 中的 ret 为 2,进程 2 中的 ret 为 0。
  • 在进程 1 中,由于 ret 非零,因此不会发生分叉。
  • 在进程2中,ret为0,因此我们fork了一个进程ID为3的子进程。
  • 现在进程1、2、3中的ret分别为2、3、0。
  • 现在进程 3 将分叉一个新的子进程。

It's a short-circuit logical AND. If ret is 0, then it will execute the fork(). If not, it won't. I can walk through the code for you.

//we fork a child process
int ret = fork();

//ret is 0 if we are in the child process, -1 if fork failed
//otherwise ret is the process id of the child process

//because of this, the fork below executes only within the child process
ret = ret && fork(); /* Here is where I am confused*/

//at this point, if we did fork a process (in the child), then ret is 0 in the child
//then we fork again
if(ret == 0) {
    fork();
}

So we have our first process, process 1 executing this code. Let's assume all forks are successful (but you should make sure to check this... I think it should be handled within the existing code but it isn't that obvious).

  • Process 1 forks, creating a child process with process ID 2.
  • ret is now 2 in process 1 and 0 in process 2.
  • In process 1, since ret is non-zero, no fork happens.
  • In process 2, ret is 0, so we fork a child process with process ID 3.
  • Now ret in process 1, 2, and 3 are 2, 3, and 0, respectively.
  • Now process 3 will fork a new child.
后来的我们 2025-01-12 22:42:37

第一个分叉 ret - fork() 将导致 3 种可能的结果:

  • > 0 =>父进程获取子进程的 pid
  • = 0 =>子进程
  • < 0 => fork 错误

第二个 fork,ret = ret && fork(),仅当 ret 非零时才会执行 fork()。这可能发生在父级良好情况和父级错误情况中。该语句的结果可以是:

  • == 0 => ret 不为零,fork() 为零。
  • != 0 => ret 不为零,fork() 不为零。

第三个 fork if (ret == 0) { fork() } 仅当 ret 为零时才会执行。

那么这一切意味着什么呢?第二个分叉似乎很可疑,因为在父级成功或失败的情况下,第一个分叉的返回值可能不为零!我不知道这是否是预期的结果,但似乎值得怀疑。

如果第一个分叉返回在子级中,则第三个分叉将会发生,第二个分叉不会被执行,但第三个分叉会执行。如果第一个 fork 在父上下文中并且第二个 fork 在子上下文中,则第三个 fork 也可以被执行。

有人检查这个逻辑,因为我永远不会写这种代码。

The first fork, ret - fork(), will result in 3 possible outcomes:

  • > 0 => parent gets pid of child
  • = 0 => child process
  • < 0 => error with fork

The second fork, ret = ret && fork(), will execute the fork() only if ret is nonzero. This can happen in the parent good case and the parent error case. The result of this statement can be:

  • == 0 => ret was nonzero and fork() is zero.
  • != 0 => ret was nonzero and fork() was nonzero.

The third fork, if (ret == 0) { fork() }, will only execute if ret is zero.

So what does all of this mean? The second fork seems suspect in that the return value from the first fork could be nonzero in the case of a parent success or failure! I don't know if this was the intended result, but it seems dubious.

The third fork would happen if the first fork return was in the child, the second fork doesn't get executed, but the third does. The third fork can also get executed if the first fork is in the parent context and the second fork is in the child context.

Someone check this logic as I could never write this kind of code.

尬尬 2025-01-12 22:42:37

在C语言中,&&运算符的作用是这样的:

  1. 计算第一个参数。如果为零,则不计算第二个参数,结果为 0。
  2. 如果第一个参数不为零,则计算第二个参数。如果它是 0,则答案是 0。否则,它是 1。

函数 fork 返回 0 给子进程,另一个数字(子进程的 pid)返回给父进程,所以在你的第一个 之后fork,在父进程中ret>0,在子进程中,ret==0。如果取消第一个 printf 的注释,您将得到 0 和另一个数字。

然后,你运行你的线路。在子进程中,ret为0,因此&&的计算在fork之前停止,ret仍为0。在父亲中,ret>0,因此它运行fork(),并创建另一个孩子。在父进程中,fork返回正数,因此ret将为1,而在第二个子进程中,fork返回0,因此>ret 将为 0。
因此,如果您仅取消注释第二个 printf,您将得到 0,0,1 (也许在不同的命令)。

然后,执行 if (ret==0) fork();,这样两个子进程(其 ret 为 0)都会创建新进程。现在,您总共有 5 个进程,因此 Hello world\n 行将被打印 5 次。

(在搞乱 fork 的同时使用输出函数是相当危险的 - 您有 5 个进程在没有任何锁定的情况下写入同一文件,因此您可以获得类似 HHHHHeeeeellllllllooooo wwwwwooooorrrrrlllllddddd\n\n\ 的结果n\n\n)

In C language, the act of the && operator is so:

  1. Calculate the first argument. if it's zero, don't calculate the second argument, and the result is 0.
  2. If the first argument isn't zero, calculate the second argument. if it's zero, the answer is 0. else, it's 1.

The function fork return 0 to the child process, and another number (the child's pid) to the father, so after your first fork, in the father process ret>0, and in the child process, ret==0. If you uncomment the first printf, you will get 0 and another number.

Then, you run your line. In the child, ret is 0, so the calculating of the && is stopped before of the fork, and ret remains 0. In the father, ret>0, so it runs fork(), and create another child. In the father process, fork return positive number, so ret will be 1, and in the second child, fork return 0, so ret will be 0.
So, if you uncomment only the second printf, you will get 0,0,1 (Maybe in different order).

Then, you do if (ret==0) fork();, so the both children (whose ret is 0) create new process each. Now, you have totally 5 processes, so the line Hello world\n will be printed 5 times.

(It's pretty dangerous to use output functions while messing with fork - you have 5 processes that write to the same file without any locking, so you can get results like HHHHHeeeeellllllllllooooo wwwwwooooorrrrrlllllddddd\n\n\n\n\n)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文