+ -
当前位置:首页 → 问答吧 → 外部或static变量的生存期长于main()函数?

外部或static变量的生存期长于main()函数?

时间:2010-06-28

来源:互联网

出处:Andrew Koenig  C 陷阱与缺陷 ,高巍 译,人民邮电出版社 2002.11 , 86~88页
  1. #include <stdio.h>

  2. main( )
  3. {
  4.   int c ;
  5.   char buf[BUFSIZ];
  6.   setbuf(stdout ,buf);
  7.   while((c=getchar()) != EOF)
  8.      putchar(c);
  9. }
复制代码
Andrew Koenig认为这个程序是错误的,因为buf在main函数结束前已经被释放
他提出的一种改正方案是:把buf改为在函数外部定义或定义为局部的 static char buf[BUFSIZ];
这在本质上是假设了外部或static变量的生存期长于main()函数

我认为这是错误的
想听听大家的高见

作者: pmerofc   发布时间: 2010-06-28

被贴个“用汇编解释C语言”的标签的路过。

作者: 没本   发布时间: 2010-06-28

回复 没本


    哈哈,念念不忘么

作者: pmerofc   发布时间: 2010-06-28

本帖最后由 没本 于 2010-06-28 21:43 编辑

如果你认为main()就是进程的起点,main()返回就是进程的终点,当然可以认为《C 陷阱与缺陷》里是错的。

作者: 没本   发布时间: 2010-06-28

是的,长于main。

static变量,我认为他的生存期从加载器将程序加载完毕后开始,而main则是程序开始执行后开始。

那个《Linux编程一站式学习》有讲到,其实main函数是被一段汇编代码调用的,这段汇编代码生成的目标文件会被链接器链接。

作者: zhaohongjian000   发布时间: 2010-06-28

进程应该是超出C语言的一个概念了吧
退一步讲,即使不认为main()返回就是进程的终点
难道Andrew Koenig的看法就成立么?
我还是看不出他说的有什么根据

作者: pmerofc   发布时间: 2010-06-28

本帖最后由 zhaohongjian000 于 2010-06-28 21:52 编辑

static变量,我认为他的生存期从加载器将程序加载完毕后开始,而main则是程序开始执行后开始。

---------------------------------------------------------------------------------------------

我认为如果我这句没说错,是可以作为依据的。拥有静态生存期的变量的初始化应该是由加载器在加载过程中完成,不属于程序执行的流程。既然程序还未执行就以存在,自然生存期更长了。

同样的,拥有静态生存期的变量的回收也不属于程序执行的流程,程序执行完后由系统负责。

作者: zhaohongjian000   发布时间: 2010-06-28

Andrew Koenig可不像谭浩强那么容易批的,等熟悉glibc的牛人来批楼主吧。我就不用汇编献丑了。

作者: 没本   发布时间: 2010-06-28



QUOTE:
Andrew Koenig可不像谭浩强那么容易批的,等熟悉glibc的牛人来批楼主吧。我就不用汇编献丑了。
没本 发表于 2010-06-28 21:51


谢谢
要是汇编就没必要了

作者: pmerofc   发布时间: 2010-06-28

本帖最后由 fera 于 2010-06-28 22:01 编辑

没本正解!

maij()退出后,操作系统会做一些清理工作。
在程序退出前,清理程序的资源,然后再消除虚拟内存和物理内存之间的映射。而static变量放在全局数据段里。清理资源包括关闭/flush文件等,然后才是回收内存。

从内核源码来看,至少linux和symbian os是这么干的。

作者: fera   发布时间: 2010-06-28



QUOTE:
是的,长于main。

static变量,我认为他的生存期从加载器将程序加载完毕后开始,而main则是程序开始执行 ...
zhaohongjian000 发表于 2010-06-28 21:43




    好吧。
    就按你的思路说下去
    问题在于“加载完毕”和“开始执行 ”有间隙吗?(以及执行结束与卸载完毕)
    这个间隙可以做什么?

作者: pmerofc   发布时间: 2010-06-28

  1. $ cat n.cpp
  2. #include<stdio.h>
  3. struct gb
  4. {
  5.         gb() { puts("hi main()\n"); }
  6.         ~gb() { puts("bye main()\n"); }
  7. } g;
  8. int main()
  9. {
  10.         puts("main: hi all\n");
  11.         return 0;
  12. }
  13. $ g++ n.cpp -o n
  14. $ ./n
  15. hi main()

  16. main: hi all

  17. bye main()
复制代码

作者: 没本   发布时间: 2010-06-28



QUOTE:
好吧。
    就按你的思路说下去
    问题在于“加载完毕”和“开始执行 ”有间隙吗?(以及执行 ...
pmerofc 发表于 2010-06-28 21:55



这个超出范围了。我没有看过任何一个加载器的实现,加载完成后应该(猜的)跳转到程序入口开始执行。进程执行完毕系统怎么回收都行,可以立刻回收,也可以等一会,完全是系统的事了。总之这个超出语言本身范围了。我猜C的ISO文档上应该有说明静态生存期变量的有效范围吧,我英语不好,就不自己看了。

作者: zhaohongjian000   发布时间: 2010-06-28

  1. $ cat e.c
  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. void bye(void) { puts("bye main()\n"); }

  5. int main(void)
  6. {
  7.         atexit(bye);
  8.         puts("main: hi all!\n");
  9.         return 0;
  10. }

  11. $ gcc -o e e.c
  12. $ ./e
  13. main: hi all!

  14. bye main()

  15. $
复制代码

作者: 没本   发布时间: 2010-06-28



QUOTE:
没本 发表于 2010-06-28 21:56




    例子很有趣,谢谢
    可惜是C++的

作者: pmerofc   发布时间: 2010-06-28

回复 pmerofc


    就知道你会这么说,我才先发一个C++,我又料中了。看14楼。

作者: 没本   发布时间: 2010-06-28



QUOTE:
回复  pmerofc


    就知道你会这么说,我才先发一个C++。看14楼。
没本 发表于 2010-06-28 22:07



问题的核心在于,
如果存在时间间隔
那么在这个间隔之中,谁可以做什么?

作者: pmerofc   发布时间: 2010-06-28

main()之后fflush()之前只要有一个函数用了栈,char buf[BUFSIZ]就被覆盖了,包括fflush()本身。

作者: 没本   发布时间: 2010-06-28



QUOTE:
main()之后fflush()之前只要有一个函数用了栈,char buf就被覆盖了,包括fflush()本身。
没本 发表于 2010-06-28 22:12




这到底是什么时候
例如?

作者: pmerofc   发布时间: 2010-06-28

Declaration:

void exit(int status);

Causes the program to terminate normally. First the functions registered by atexit are called, then all open streams are flushed and closed, and all temporary files opened with tmpfile are removed. The value of status is returned to the environment. If status is EXIT_SUCCESS, then this signifies a successful termination. If status is EXIT_FAILURE, then this signifies an unsuccessful termination. All other values are implementation-defined.

作者: zhaohongjian000   发布时间: 2010-06-28

你既然承认了main()之后还有函数运行。main(){char buf[BUFSIZ];}在main()之后无效,这是常识。你要死抗到底,寄希望于某个C编译器的crt loader在main()之后不用栈,以证明你的程序可以正常执行,那随你了。我认为我提供的证据已经非常充分了。

作者: 没本   发布时间: 2010-06-28



QUOTE:
你既然承认了main()之后还有函数运行。main(){char buf;}在main()之后无效,这是常识。你要死抗到底,寄希望 ...
没本 发表于 2010-06-28 22:18



“你既然承认了main()之后还有函数运行。”这个我没承认,实际上恰恰是我希望弄清楚的
“main(){char buf;}在main()之后无效,这是常识。”,这个没问题,我不反对这个常识

谢谢

作者: pmerofc   发布时间: 2010-06-28

6.2.4 Storage durations of objects
3 An object whose identifier is declared with external or internal linkage, or with the
storage-class specifier static has static storage duration. Its lifetime is the entire
execution of the program and its stored value is initialized only once, prior to program
startup.

作者: OwnWaterloo   发布时间: 2010-06-28