我想知道在C中调用fork((后,char数组是否会重复。例如,在下面的例子中是输出:
The message in child is secret message
The message in parent is secret message
或
The message in child is secret message
The message in parent is empty message
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
char msg[50] = "empty message";
pid_t pid = fork();
if(pid > 0) {
wait(0);
printf("The message in parent is %sn", msg);
} else {
strcpy(msg, "secret message");
printf("The message in child is %sn", msg);
}
return 0;
}
我想用一个有趣的实验来回答你。这里有一个类似但更简单的代码版本:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int x = 10;
int *px = &x;
pid_t pid = fork();
if(pid > 0) {
wait(0);
printf("x in parent is %dn", *px);
} else {
*px = 20;
printf("x in child is %dn", *px);
}
return 0;
}
其中,我使用了一个由子进程修改的整数来简化程序集。如果我们编译并停在生成的程序集上(我用ARM编译器做的,我对它更熟悉(,我们可以看到值10保存在sp-16
的堆栈上,而x的地址保存在sp-24
mov w0, 10 // x = 10
str w0, [sp, 16]
add x0, sp, 16 // px = &x
str x0, [sp, 24]
在子分支中,我们通过从堆栈中检索地址并在该地址写入新值来修改x
的值。
ldr x0, [sp, 24] // *px = 20;
mov w1, 20
str w1, [x0]
ldr x0, [sp, 24] // Load value of x and print it with message
ldr w0, [x0]
mov w1, w0
adrp x0, .LC1
add x0, x0, :lo12:.LC1
bl printf
所以sp-24
的值现在改变了,对吗?那么,当执行父代码时,如何可能:
ldr x0, [sp, 24] // Load value of x and print it with message
ldr w0, [x0]
mov w1, w0
adrp x0, .LC0
add x0, x0, :lo12:.LC0
bl printf
b .L3
我们从相同的地址加载,但我们仍然得到值10
?
x in child is 20
x in parent is 10
正如评论中指出的那样,答案是每个进程都有自己的地址空间。地址空间包含堆栈、堆、映射页等。然而,在fork上,地址空间完全相同,因此我们可以在这两种情况下从相同的地址加载x
。