什么是 (fork() && fork()) ||叉()打印?
What does (fork() && fork()) || fork() print?
我试图理解这段代码到底打印了什么
int main(void) {
pid_t r = (fork() && fork()) || fork();
if (r) {
printf("a");
} else {
printf("b");
}
}
我特别想了解将打印多少个“a”和“b”。
我找到的第一个解决方案是:3个“a”和2个“b”
但我不太确定,顺便说一句,我认为这可能是解释:
第一个fork()
returns 0到child进程(p1)和一个non-zero值到parent(p0)所以children returns 0 的 &&
运算符和 ||
的短路被采用,需要对其进行评估。
此时 p1 将 fork()
一个 child 进程 (p2) 具有相应的 return 值(p1 为 0,p2 为 non-zero)。
在这个操作之后,p1 的变量 r
是一个 non-zero 值,而 p2 的变量是 0。
这意味着程序将打印“a”和“b”。
回到p0,由于&&
的左边部分是non-zero值,需要计算右边的值,所以会有另一个fork()
会return 一个 non-zero 值到 p0 和 0 到 child 进程 (p3)。
现在我们需要检查 ||
运算符发生了什么:
- p0 出来一个 non-zero 值所以我们不需要评估
||
的正确部分
- p0 将有
r
= non-zero
- 输出将为“b”
- p3 结果为 0,我们需要评估
||
的右边部分
- 会有
fork()
调用,另一个 child (p4) 将被创建,return 值 = 0 并且 p4 的 r
值也将是0,而 p3 的 r
值将是 non-zero,因此打印为“a”和“b”。
我知道这类问题已经收到回复,但我只是想确保我的推理是有道理的。
我认为你解释的很正确。
这里有一个table可以通过这段代码总结不同的场景:
r
0
1
1
0
1
p1
0
0
p1
p1
p1
p2
NA
NA
0
0
p2
p3
0
p3
p3
0
NA
注:p1
指第一个childPID,p2
指第二个child,p3
指第三个child. NA
表示对应的fork()
不会因为short-circuit求值而被调用
可以看到,if(r)
会被求五次,被取三次(r
被求为true
),两次不会被取( r
被评估为 false)。
我们知道的:
- 来自
man fork
:fork()
应 return 0 到 child 进程并且应 return child 进程到 parent 进程。
- PID 总是 non-zero。
||
和 &&
是 short-circuited。
&&
当左侧非零时不执行右侧。
||
左边为零时不执行右边
||
当边之一不为零时为真。
&&
两边均为非零时为真。
- false 为零,true 为非零。
好的,接下来会发生什么:
pid_t r = (fork() && fork()) || fork();
让我们将其总结为 table。每个 r =
第一行 fork()
都是粗体 - 这意味着这个 fork()
将被执行。当 child 具有 fork() = 0
时,这意味着它是“生成的” - parent 具有 child 的 PID,然后作为 [=12= 的 return 值].
stage
main process
child1
child2
child3
child4
r =
(fork() && fork()) || fork()
fork()=
child1pid
0
r =
(child1pid && fork()) || fork()
(0 && ignored) || fork()
fork()=
child2pid
child3pid
0
0
r =
(child1pid && child2pid) || ignored
(0 && ignored) || childpid3
(child1pid && 0) || fork()
(0 && ignored) || 0
fork()=
child4pid
0
r =
(child1pid && child2pid) || ignored
(0 && ignored) || childpid3
(child1pid && 0) || child4pid
(0 && ignored) || 0
(child1pid && 0) || 0
r =
true || ignored
false || childpid3
false || child4pid
false || 0
false || 0
r =
true
true
true
false
false
print
a
a
a
b
b
3 次 a
和 2 次 b
将被打印。
如果你在程序中下点功夫,你可以自己测试一下:
- 检查您系统的最大 pid:
cat /proc/sys/kernel/pid_max
并打印所有 fork
return 值
#define PIDMAX (4194304 + 1)
//4194304 - max pid value for my system
int main(void) {
pid_t p[3] = {PIDMAX , PIDMAX, PIDMAX};
bool r = ((p[0] = fork()) && (p[1] = fork())) || (p[2] = fork());
if (r) {
printf("a\n");
} else {
printf("b\n");
}
for(size_t i = 0; i < sizeof(p) / sizeof(p[0]); i ++)
{
if(p[i] == PIDMAX ) printf("N/A%s", (i == sizeof(p) / sizeof(p[0]) - 1) ? "\n" : ", ");
else printf("%ld%s", (long)p[i], (i == sizeof(p) / sizeof(p[0]) - 1) ? "\n" : ", ");
}
}
我系统上的输出:
a
5609, 5610, N/A
a
0, N/A, 5611
a
5609, 0, 5612
b
5609, 0, 0
b
0, N/A, 0
或
a
5733, 5734, N/A
b
0, N/A, 0
a
0, N/A, 5736
a
5733, 0, 5735
b
5733, 0, 0
取决于 运行
我试图理解这段代码到底打印了什么
int main(void) {
pid_t r = (fork() && fork()) || fork();
if (r) {
printf("a");
} else {
printf("b");
}
}
我特别想了解将打印多少个“a”和“b”。 我找到的第一个解决方案是:3个“a”和2个“b” 但我不太确定,顺便说一句,我认为这可能是解释:
第一个fork()
returns 0到child进程(p1)和一个non-zero值到parent(p0)所以children returns 0 的 &&
运算符和 ||
的短路被采用,需要对其进行评估。
此时 p1 将 fork()
一个 child 进程 (p2) 具有相应的 return 值(p1 为 0,p2 为 non-zero)。
在这个操作之后,p1 的变量 r
是一个 non-zero 值,而 p2 的变量是 0。
这意味着程序将打印“a”和“b”。
回到p0,由于&&
的左边部分是non-zero值,需要计算右边的值,所以会有另一个fork()
会return 一个 non-zero 值到 p0 和 0 到 child 进程 (p3)。
现在我们需要检查 ||
运算符发生了什么:
- p0 出来一个 non-zero 值所以我们不需要评估
||
的正确部分- p0 将有
r
= non-zero - 输出将为“b”
- p0 将有
- p3 结果为 0,我们需要评估
||
的右边部分- 会有
fork()
调用,另一个 child (p4) 将被创建,return 值 = 0 并且 p4 的r
值也将是0,而 p3 的r
值将是 non-zero,因此打印为“a”和“b”。
- 会有
我知道这类问题已经收到回复,但我只是想确保我的推理是有道理的。
我认为你解释的很正确。
这里有一个table可以通过这段代码总结不同的场景:
r | 0 | 1 | 1 | 0 | 1 |
---|---|---|---|---|---|
p1 | 0 | 0 | p1 | p1 | p1 |
p2 | NA | NA | 0 | 0 | p2 |
p3 | 0 | p3 | p3 | 0 | NA |
注:p1
指第一个childPID,p2
指第二个child,p3
指第三个child. NA
表示对应的fork()
不会因为short-circuit求值而被调用
可以看到,if(r)
会被求五次,被取三次(r
被求为true
),两次不会被取( r
被评估为 false)。
我们知道的:
- 来自
man fork
:fork()
应 return 0 到 child 进程并且应 return child 进程到 parent 进程。 - PID 总是 non-zero。
||
和&&
是 short-circuited。&&
当左侧非零时不执行右侧。||
左边为零时不执行右边||
当边之一不为零时为真。&&
两边均为非零时为真。- false 为零,true 为非零。
好的,接下来会发生什么:
pid_t r = (fork() && fork()) || fork();
让我们将其总结为 table。每个 r =
第一行 fork()
都是粗体 - 这意味着这个 fork()
将被执行。当 child 具有 fork() = 0
时,这意味着它是“生成的” - parent 具有 child 的 PID,然后作为 [=12= 的 return 值].
stage | main process | child1 | child2 | child3 | child4 |
---|---|---|---|---|---|
r = | (fork() && fork()) || fork() | ||||
fork()= | child1pid | 0 | |||
r = | (child1pid && fork()) || fork() | (0 && ignored) || fork() | |||
fork()= | child2pid | child3pid | 0 | 0 | |
r = | (child1pid && child2pid) || ignored | (0 && ignored) || childpid3 | (child1pid && 0) || fork() | (0 && ignored) || 0 | |
fork()= | child4pid | 0 | |||
r = | (child1pid && child2pid) || ignored | (0 && ignored) || childpid3 | (child1pid && 0) || child4pid | (0 && ignored) || 0 | (child1pid && 0) || 0 |
r = | true || ignored | false || childpid3 | false || child4pid | false || 0 | false || 0 |
r = | true | true | true | false | false |
a | a | a | b | b |
3 次 a
和 2 次 b
将被打印。
如果你在程序中下点功夫,你可以自己测试一下:
- 检查您系统的最大 pid:
cat /proc/sys/kernel/pid_max
并打印所有 fork
return 值
#define PIDMAX (4194304 + 1)
//4194304 - max pid value for my system
int main(void) {
pid_t p[3] = {PIDMAX , PIDMAX, PIDMAX};
bool r = ((p[0] = fork()) && (p[1] = fork())) || (p[2] = fork());
if (r) {
printf("a\n");
} else {
printf("b\n");
}
for(size_t i = 0; i < sizeof(p) / sizeof(p[0]); i ++)
{
if(p[i] == PIDMAX ) printf("N/A%s", (i == sizeof(p) / sizeof(p[0]) - 1) ? "\n" : ", ");
else printf("%ld%s", (long)p[i], (i == sizeof(p) / sizeof(p[0]) - 1) ? "\n" : ", ");
}
}
我系统上的输出:
a
5609, 5610, N/A
a
0, N/A, 5611
a
5609, 0, 5612
b
5609, 0, 0
b
0, N/A, 0
或
a
5733, 5734, N/A
b
0, N/A, 0
a
0, N/A, 5736
a
5733, 0, 5735
b
5733, 0, 0
取决于 运行