头文件中的static变量

m_o_n_e_y 2014-03-01 08:53:08
在cal.h文件中是这样的:
#ifndef CAL_H
#define CAL_H
#define NUMBER '0'

static int test_include = 100;

void push(double);
double pop(void);
int getop(char[]);
int getch(void);
void ungetch(int);
#endif


在stack.c文件中是这样的:
#include "cal.h"
void push(double c)
{
test_include += 20;
}

在getop.c中是这样的:
#include "cal.h"
int getop(char s[])
{
test_include = 58;
return 0;
}

在getch.c中是这样的:
#include "cal.h"
int getch(void)
{
test_include -= 10;
return 0;
}

在main.c中是这样的:
#include "cal.h"
#include <stdio.h>
void main()
{
char s[10];
push(0);
printf("%d\n", test_include);
getch();
printf("%d\n", test_include);
getop(s);
printf("%d\n", test_include);
}

小弟单步调试,被调用的三个函数都能进去,并且在函数里面test_include的值是已经被改变了的。但是输出的结果如下:
小弟在发此贴之前对#include 和static的理解如下:
1、#include指令会将被include进来的文件拷贝一个副本,并且把副本引入。
2、static修饰外部变量,会将外部变量的作用域限制在本文件之内,而将其include的文件访问不到这个变量。
小弟的疑问是:
1、在三个文件的三个函数中都没报错,且在函数里面test_include的值已经被改变,然而,输出的test_include的值却没变。
2、如果去掉cal.h文件里static int test_include = 100;的static其它地方不变,那么输出如下
三个文件引入的cal.h不是把副本引入么,但是为何三个函数修改的是同一个变量?

究竟这个#include和static的作用和机制是什么!
请各位前辈指教!
多谢!!
...全文
692 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
Huhaskii 2016-06-30
  • 打赏
  • 举报
回复
baichi4141 讲的准确清晰,赞一个。
gaoon 2014-03-04
  • 打赏
  • 举报
回复
引用 10 楼 M_o_n_e_y 的回复:
[quote=引用 9 楼 baichi4141 的回复:] [quote=引用 8 楼 M_o_n_e_y 的回复:] [quote=引用 3 楼 baichi4141 的回复:] 楼主有一个基本概念没有理解,就是“预编译”和“编译”的区别 说的简单一点,编译是把源代码变成机器命令,预编译则是对源代码进行一些简单处理,这是完全独立的两个阶段 #include是预编译指令,作用是把指定文件的内容复制到当前文件当前行处 static是一个关键字,它的作用由语言标准规定,在编译时起到特定的作用 由此可以看出,static跟#include完全没有任何关系,在编译器编译源代码前,#include就已经完成其任务,编译器在处理static时,根本不知道当前这行代码是否被#include过多少次 所以“static修饰外部变量,会将外部变量的作用域限制在本文件之内,而将其include的文件访问不到这个变量”这个想法是错误的,static限定的“本文件”是“所有预编译指令执行后的文件”。如果你在一个头文件里定义了static全局变量,在几个源文件中包含这个头文件,结果就是这几个源文件分别都有了一个static全局变量 这就是不管你在其他几个源文件里怎么改,负责输出的那个源文件输出的值永远不变的原因,因为这几个源文件都有一个叫这个名字的变量,这几个变量彼此之间没有任何关系
小弟还是对第二种输出结果(在头文件定义的变量被3个文件修改了)还是有疑惑。小弟的理解是这样的:#include将代码copy进来到那三个c文件,形成的临时文件中都各有各自的test_include呀,那么编译的时候应该编译的是copy(预编译)完成以后的临时文件,则,test_include应该是各自文件里面的,三个文件互不影响其它文件的test_include。[/quote] #include之后每个源文件编译之后的模块都有一个同名变量,没用static所以这个变量对其他源文件编译之后的模块就是可见的 我不熟悉C语言中关于声明和定义的标准所以没有说,从结果来看似乎是你用的C编译器将这些源于同一个头文件的同名变量整合成一个变量了 在C++语言中,你这种写法直接通不过编译,报错“多个模块有同名全局变量”[/quote]我用的vc++6.0写的代码。C++我没试过。[/quote] cal.h文件删除static后,clean一下工程,再重新编译,应该就编译不过了。 报错和C++都是一样的。
Adol1111 2014-03-03
  • 打赏
  • 举报
回复
引用 11 楼 M_o_n_e_y 的回复:
[quote=引用 5 楼 Adol1111 的回复:] 即使在头文件里,进行了特殊处理,全局变量还是全局变量。 在大型项目中,非常容易出问题。 而且头文件中定义变量最好是用extern 而不是static ,这两者是有差异的!! static允许其他地方有重复,而extern不可以。 简单说就是,C/C++的文件都是单独编译的,每一个编译后的文件由连接器组成一个可执行文件。 对于static来说,每个引用该头文件的编译单元都允许有一份,但组成的最终文件不冲突。 而extern来说,是完全共享的,所有引用都是外部的,所以a文件改了,b文件也会受影响。
请看8楼和3楼,然后指教小弟,为何两次输出的结果是如此。谢谢。[/quote] 都说了说static的作用域是本文件了,你在main.c以外的文件里修改这个变量,是不影响main.c中的test_include 所以最后输出结果都是相同的。 如果你想看到变化的话,改成extern(extern不能再定义时初始化,不然extern就无效了,头文件声明,在main.c中赋值)
zhxianbin 2014-03-03
  • 打赏
  • 举报
回复
每个文件 #include "cal.h" 后都定义了 static int test_include = 100; 所以互不影响。 如 1F 所说不应该使用这种写法,哪个文件要用static变量就在哪个文件定义,不应放入头文件
WizardOz 2014-03-03
  • 打赏
  • 举报
回复
确定无疑,gcc编译器不能通过编译。理论上也不能通过编译。 应该是你的编译器蛋疼了。
WizardOz 2014-03-03
  • 打赏
  • 举报
回复
第一次输出 100 100 100是因为两个文件中有各自的 “test_include” 变量,因为你加了static,所以每个文件“stack.c”“main.c”访问的是自己的“test_include”变量。你调用的push、pop改变了stack.c中的test_include变量,没有改变main.c中的! 如果你把输出函数写在stack.c中,然后在main.c中调用,你就会发现输出变化了。 至于去掉static以后,为什么你还能编译,这个我不能理解。在gcc编译器应该编译不了了,命名冲突,两个变量用了同一个名字。
m_o_n_e_y 2014-03-02
  • 打赏
  • 举报
回复
引用 3 楼 baichi4141 的回复:
楼主有一个基本概念没有理解,就是“预编译”和“编译”的区别 说的简单一点,编译是把源代码变成机器命令,预编译则是对源代码进行一些简单处理,这是完全独立的两个阶段 #include是预编译指令,作用是把指定文件的内容复制到当前文件当前行处 static是一个关键字,它的作用由语言标准规定,在编译时起到特定的作用 由此可以看出,static跟#include完全没有任何关系,在编译器编译源代码前,#include就已经完成其任务,编译器在处理static时,根本不知道当前这行代码是否被#include过多少次 所以“static修饰外部变量,会将外部变量的作用域限制在本文件之内,而将其include的文件访问不到这个变量”这个想法是错误的,static限定的“本文件”是“所有预编译指令执行后的文件”。如果你在一个头文件里定义了static全局变量,在几个源文件中包含这个头文件,结果就是这几个源文件分别都有了一个static全局变量 这就是不管你在其他几个源文件里怎么改,负责输出的那个源文件输出的值永远不变的原因,因为这几个源文件都有一个叫这个名字的变量,这几个变量彼此之间没有任何关系
小弟还是对第二种输出结果(在头文件定义的变量被3个文件修改了)还是有疑惑。小弟的理解是这样的:#include将代码copy进来到那三个c文件,形成的临时文件中都各有各自的test_include呀,那么编译的时候应该编译的是copy(预编译)完成以后的临时文件,则,test_include应该是各自文件里面的,三个文件互不影响其它文件的test_include。
m_o_n_e_y 2014-03-02
  • 打赏
  • 举报
回复
引用 2 楼 haolly 的回复:
static 变量 不是只能在static函数中使用吗? 一般都是在头文件中用extern声明的,然后在c文件中定义。
static 变量 不是只能在static函数中使用吗?这句话何解?
m_o_n_e_y 2014-03-02
  • 打赏
  • 举报
回复
引用 1 楼 taodm 的回复:
就绝对不可以在头文件里定义变量,不管是否加static 研究其出错细节,基本属浪费生命。
请指教!
m_o_n_e_y 2014-03-02
  • 打赏
  • 举报
回复
引用 5 楼 Adol1111 的回复:
即使在头文件里,进行了特殊处理,全局变量还是全局变量。 在大型项目中,非常容易出问题。 而且头文件中定义变量最好是用extern 而不是static ,这两者是有差异的!! static允许其他地方有重复,而extern不可以。 简单说就是,C/C++的文件都是单独编译的,每一个编译后的文件由连接器组成一个可执行文件。 对于static来说,每个引用该头文件的编译单元都允许有一份,但组成的最终文件不冲突。 而extern来说,是完全共享的,所有引用都是外部的,所以a文件改了,b文件也会受影响。
请看8楼和3楼,然后指教小弟,为何两次输出的结果是如此。谢谢。
m_o_n_e_y 2014-03-02
  • 打赏
  • 举报
回复
引用 9 楼 baichi4141 的回复:
[quote=引用 8 楼 M_o_n_e_y 的回复:] [quote=引用 3 楼 baichi4141 的回复:] 楼主有一个基本概念没有理解,就是“预编译”和“编译”的区别 说的简单一点,编译是把源代码变成机器命令,预编译则是对源代码进行一些简单处理,这是完全独立的两个阶段 #include是预编译指令,作用是把指定文件的内容复制到当前文件当前行处 static是一个关键字,它的作用由语言标准规定,在编译时起到特定的作用 由此可以看出,static跟#include完全没有任何关系,在编译器编译源代码前,#include就已经完成其任务,编译器在处理static时,根本不知道当前这行代码是否被#include过多少次 所以“static修饰外部变量,会将外部变量的作用域限制在本文件之内,而将其include的文件访问不到这个变量”这个想法是错误的,static限定的“本文件”是“所有预编译指令执行后的文件”。如果你在一个头文件里定义了static全局变量,在几个源文件中包含这个头文件,结果就是这几个源文件分别都有了一个static全局变量 这就是不管你在其他几个源文件里怎么改,负责输出的那个源文件输出的值永远不变的原因,因为这几个源文件都有一个叫这个名字的变量,这几个变量彼此之间没有任何关系
小弟还是对第二种输出结果(在头文件定义的变量被3个文件修改了)还是有疑惑。小弟的理解是这样的:#include将代码copy进来到那三个c文件,形成的临时文件中都各有各自的test_include呀,那么编译的时候应该编译的是copy(预编译)完成以后的临时文件,则,test_include应该是各自文件里面的,三个文件互不影响其它文件的test_include。[/quote] #include之后每个源文件编译之后的模块都有一个同名变量,没用static所以这个变量对其他源文件编译之后的模块就是可见的 我不熟悉C语言中关于声明和定义的标准所以没有说,从结果来看似乎是你用的C编译器将这些源于同一个头文件的同名变量整合成一个变量了 在C++语言中,你这种写法直接通不过编译,报错“多个模块有同名全局变量”[/quote]我用的vc++6.0写的代码。C++我没试过。
baichi4141 2014-03-02
  • 打赏
  • 举报
回复
引用 8 楼 M_o_n_e_y 的回复:
[quote=引用 3 楼 baichi4141 的回复:] 楼主有一个基本概念没有理解,就是“预编译”和“编译”的区别 说的简单一点,编译是把源代码变成机器命令,预编译则是对源代码进行一些简单处理,这是完全独立的两个阶段 #include是预编译指令,作用是把指定文件的内容复制到当前文件当前行处 static是一个关键字,它的作用由语言标准规定,在编译时起到特定的作用 由此可以看出,static跟#include完全没有任何关系,在编译器编译源代码前,#include就已经完成其任务,编译器在处理static时,根本不知道当前这行代码是否被#include过多少次 所以“static修饰外部变量,会将外部变量的作用域限制在本文件之内,而将其include的文件访问不到这个变量”这个想法是错误的,static限定的“本文件”是“所有预编译指令执行后的文件”。如果你在一个头文件里定义了static全局变量,在几个源文件中包含这个头文件,结果就是这几个源文件分别都有了一个static全局变量 这就是不管你在其他几个源文件里怎么改,负责输出的那个源文件输出的值永远不变的原因,因为这几个源文件都有一个叫这个名字的变量,这几个变量彼此之间没有任何关系
小弟还是对第二种输出结果(在头文件定义的变量被3个文件修改了)还是有疑惑。小弟的理解是这样的:#include将代码copy进来到那三个c文件,形成的临时文件中都各有各自的test_include呀,那么编译的时候应该编译的是copy(预编译)完成以后的临时文件,则,test_include应该是各自文件里面的,三个文件互不影响其它文件的test_include。[/quote] #include之后每个源文件编译之后的模块都有一个同名变量,没用static所以这个变量对其他源文件编译之后的模块就是可见的 我不熟悉C语言中关于声明和定义的标准所以没有说,从结果来看似乎是你用的C编译器将这些源于同一个头文件的同名变量整合成一个变量了 在C++语言中,你这种写法直接通不过编译,报错“多个模块有同名全局变量”
Adol1111 2014-03-01
  • 打赏
  • 举报
回复
即使在头文件里,进行了特殊处理,全局变量还是全局变量。 在大型项目中,非常容易出问题。 而且头文件中定义变量最好是用extern 而不是static ,这两者是有差异的!! static允许其他地方有重复,而extern不可以。 简单说就是,C/C++的文件都是单独编译的,每一个编译后的文件由连接器组成一个可执行文件。 对于static来说,每个引用该头文件的编译单元都允许有一份,但组成的最终文件不冲突。 而extern来说,是完全共享的,所有引用都是外部的,所以a文件改了,b文件也会受影响。
QZ_uitron 2014-03-01
  • 打赏
  • 举报
回复
1.首先最好不要在头文件中定义变量,除非其它模块需要调用,即是用extern定义,告诉编译器这个变量是可以被其它模块调用。 2.static是模块内的调用,不允许外部调用
baichi4141 2014-03-01
  • 打赏
  • 举报
回复
楼主有一个基本概念没有理解,就是“预编译”和“编译”的区别 说的简单一点,编译是把源代码变成机器命令,预编译则是对源代码进行一些简单处理,这是完全独立的两个阶段 #include是预编译指令,作用是把指定文件的内容复制到当前文件当前行处 static是一个关键字,它的作用由语言标准规定,在编译时起到特定的作用 由此可以看出,static跟#include完全没有任何关系,在编译器编译源代码前,#include就已经完成其任务,编译器在处理static时,根本不知道当前这行代码是否被#include过多少次 所以“static修饰外部变量,会将外部变量的作用域限制在本文件之内,而将其include的文件访问不到这个变量”这个想法是错误的,static限定的“本文件”是“所有预编译指令执行后的文件”。如果你在一个头文件里定义了static全局变量,在几个源文件中包含这个头文件,结果就是这几个源文件分别都有了一个static全局变量 这就是不管你在其他几个源文件里怎么改,负责输出的那个源文件输出的值永远不变的原因,因为这几个源文件都有一个叫这个名字的变量,这几个变量彼此之间没有任何关系
haolly 2014-03-01
  • 打赏
  • 举报
回复
static 变量 不是只能在static函数中使用吗? 一般都是在头文件中用extern声明的,然后在c文件中定义。
taodm 2014-03-01
  • 打赏
  • 举报
回复
就绝对不可以在头文件里定义变量,不管是否加static 研究其出错细节,基本属浪费生命。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧