当从执行点调用函数A时,在内部它是指向函数A的地址的JMP语句。因此当前执行点被保存到堆栈中,PC加载被调用函数的地址A并继续。
要在函数调用之后返回执行点,功能块应该具有相同的推送并弹出到堆栈上。通常在退出函数的C中,定义的堆栈变量被销毁(我认为这意味着从堆栈中弹出),但我决定在我的函数中定义一个文件描述符变量。代码如下:
void main() {
printf("In the beginning there was main()\n");
func_call();
printf("func_call complete\n");
while(1);
}
void func_call() {
int fp;
//Opening a file to get handle to it.
fp = open("stack_flush.c", O_RDONLY);
if (fp < 0 ) {
perror("fp could not open stack_flush.c");
return;
}
}
在运行此程序并检查lsof时,我可以看到fd在退出函数func_call()时仍处于打开状态。
stack_flu 3791 vvdnlt260 0u CHR 136,1 0t0 4 /dev/pts/1
stack_flu 3791 vvdnlt260 1u CHR 136,1 0t0 4 /dev/pts/1
stack_flu 3791 vvdnlt260 2u CHR 136,1 0t0 4 /dev/pts/1
stack_flu 3791 vvdnlt260 3r REG 8,3 526 24660187 /home/vvdnlt260/Nishanth/test_space/stack_flush.c
我检查了wikipedia条目中的文件描述符,我发现了这个:
为了执行输入或输出,进程通过系统调用将文件描述符传递给内核,内核将代表进程访问文件。该进程无法直接访问文件或inode表。
从上面的陈述中可以明显看出,文件描述符整数值存储在进程内存中,但是虽然它是在函数中定义的,但是文件描述符并不是函数本地的,因为它在函数退出时没有被删除。
所以我的问题是2折:
1)如果文件描述符是func_call()堆栈的一部分,那么代码如何返回到它的预函数调用执行点,尽管它还没有被弹出?同样在这种情况下,为什么在函数调用存在后它仍然存在?
2)如果不是func_call()堆栈的一部分,文件描述符在哪里驻留在进程内存中?
答案 0 :(得分:2)
变量int fd;
仅在函数func_call()
中可见,并且在此函数完成执行后,它将弹出堆栈,并且可能在输入新函数时覆盖内存。您销毁指向该文件的某些int
值这一事实并不意味着您关闭了所述文件。如果你做了类似的事情怎么办?
int global_fd;
void foo() {
int local_fd = open("bar.txt", O_RDONLY);
global_fd = local_fd;
}
并致电foo()
?您是否希望在global_fd
退出后不再使用foo
?
在这种情况下,将文件描述符视为一个指针是有帮助的,您要求内核为您提供该文件,它会为您提供一个值,您可以将其用作此特定文件的标记,令牌是你用来让内核知道像read
或lseek
这样的函数应该在哪个文件上运行的东西。当令牌传递或销毁时,文件保持打开状态,因为销毁指针不会释放分配的内存。
答案 1 :(得分:1)
当您打开文件时,内核中存储了文件描述符的表。因此,当您打开文件时,您在该表中创建了一个条目。如果您不关闭文件(使用其描述符),则永远不会删除该条目(它并不意味着您无法再次打开该文件)。
如果文件描述符是func_call()堆栈的一部分,那么代码如何返回到它的预函数调用执行点,尽管它还没有被弹出?同样在这种情况下,为什么在函数调用存在后它仍然存在?
据我所知,每个进程只有一个堆栈,而不是每个函数。因此fp
变量存储在进程的堆栈中,并在函数结束时从那里删除。
答案 2 :(得分:0)
文件描述符很特别。如你所知,他们只是整理。但它们“包含”有关正在读取的文件的大量信息(磁盘上文件的位置,读/写指针的位置内的位置等),那么存储的信息在哪里?答案是它存储在OS内核中的某个地方。它存储在OS内核中,因为它是内核管理文件I / O的工作。当我们说引用打开文件的int是“文件描述符”时,我们的意思是int指的是存储在其他地方的信息,有点像指针。那个词“描述符”很重要。有时用于这种情况的另一个词是“处理”。
如您所知,局部变量的内存通常存储在堆栈中。从函数返回时,释放函数局部变量的内存非常简单 - 它们基本上与函数的堆栈帧一起消失。当它们消失时,它们就会消失:没有办法(在C中)有一些与它们消失有关的动作。特别是,对于恰好是文件描述符的变量,无法调用close()
。
(如果你想在变量消失时进行清理操作,一种方法是使用C ++,并使用类变量,并定义一个显式的析构函数。)
当您致电malloc
时,会出现类似的情况。在这个功能中:
void f()
{
char *p = malloc(10);
}
我们调用malloc
来分配10个字节的内存并将返回的指针存储在本地指针变量p
中,当函数f
返回时它会消失。所以我们丢失了指向已分配内存的指针,但是没有调用free()
,因此内存仍然被分配。 (这是内存泄漏的示例。)