搜索
bottom↓
回复: 17

在多个.c和多个.h文件当中,如何区别全局变量和局部变量

[复制链接]

出0入0汤圆

发表于 2013-12-23 10:30:30 | 显示全部楼层 |阅读模式
1.假如现在系统中有多个.c文件和多个.h文件,一般变量声明都是放在.h文件当中,那么这种变量属于局部变量吗?如果是,那全局变量又是在哪里定义的?
2.一个.c文件要调用其它.h文件的变量时,用#include “...h”和用关键字 external  的区别?
新手求教。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入4汤圆

发表于 2013-12-23 11:01:50 | 显示全部楼层
本帖最后由 shuipaopao 于 2013-12-23 11:04 编辑

1.h文件中声明的变量是全局变量,要加external 说明,局部变量都是在子程序中声明。有谁把子程序放在.h文件中。
2.#include“.h"已经包含了.h中的宏定义,全局变量,程序声明。

出0入0汤圆

发表于 2013-12-23 11:06:31 | 显示全部楼层
赚完钱走人

出0入85汤圆

发表于 2013-12-23 10:30:31 | 显示全部楼层
区分开全局变量,模块级全局变量,局部变量就好了,每一个.C文件和其对应的.H文件称为一个模块,模块级的全局变量一般定义于.C文件中,不包含于任何函数内,且并不在.h文件中声明,有的还喜欢用static修饰。全局变量一般定义于.C文件中,是需要在.H文件中声明的,用extern修饰。局部变量是在子函数内定义的变量。分可以给我了吧

出0入0汤圆

发表于 2013-12-23 11:24:53 | 显示全部楼层
本帖最后由 qlb1234 于 2013-12-23 11:45 编辑

Variable declarations are better placed in C files.
  1. char global_a;//This variable can be accessed by all the functions, as long as they "externed" it before like "extern char global_a;".
  2. static char file_scope_b;//This variable can be accessed only by the functions later in this file and can never be "externed".
  3. void func(void)
  4. {
  5.     ...
  6.     char function_scope_c;//This variable can be accessed only by the lines below this line within this function.
  7.     ....
  8. }
复制代码

Accessing global(project scope, real global) variables in another C file.
  1. void foo(void)
  2. {
  3.     extern char global_a;
  4.     a = 21;
  5. }
复制代码

H文件並非必要的存在。#include的作用,是將目標文件的內容,全數複製至本行位置。
所以欲使global_a很方便地在其它C文件中被訪問,而又懶得每次添加extern char global_a;,其中一竅門,便是編寫一H文件,在其中加入extern char global_a;,然後在每箇欲訪問其的C文件內包含(#include)這箇H文件。

出0入0汤圆

发表于 2013-12-23 11:27:55 | 显示全部楼层
首先,没有 external 这个关键字,应该是 extern

1.假如现在系统中有多个.c文件和多个.h文件,一般变量声明都是放在.h文件当中,那么这种变量属于局部变量吗?如果是,那全局变量又是在哪里定义的?
声明在.h文件中,如果定义在函数内部,则是局部变量,定义在函数外部,则是全局变量,但是全局变量直接定义在.h文件中并不是好的做法。
eg:
sample.h

inline void foo()
{
   int a;
}

float a;

其中的int a定义了一个局部变量,float定义了一个全局变量

2.一个.c文件要调用其它.h文件的变量时,用#include “...h”和用关键字 external  的区别?
编译过程中,每一个.c文件都会首先被编译成.o或者.obj文件,如果.c或者.c中#include的所有.h中定义有变量,则这个变量就已经存在于这个.o里了
回过头看第一个问题,如果全局变量定义在.h里,并且整个工程有多个.c文件#include了这个.h,那么每个.c编译产生的.o中都有这个变量存在,最终link时,就会报错,提示这个变量已经在其他模块中存在。
所以如果整个工程项目只有一个.c文件,那么把全局变量定义在.h里没有什么大问题,但是对于比较复杂一点的工程项目,最好在.h里只是声明有这样一个变量存在,具体定义在某个.c中去做
eg:
sample.h
extern float a;

sample1.c
#include "sample.h"
float a;

void foo1()
{
    a = 1.0;
}

sample2.c
#include "sample.h"

void foo2()
{
    a = 2.0;
}

这个例子中,float a的实例只存在于 sample.o 里,sample2.o 里是没有 float a 存在的,但是由于它 #include 了 sample.h,其中又有 extern float a,所以link在一起的时候,会在其他模块中找 float a

出0入0汤圆

发表于 2013-12-23 11:34:58 来自手机 | 显示全部楼层
1,一般声明在h文件中的都是全局变量,定义在模块对应的c文件里。2,#include不过是通过预处理器把声明放在当前文件中而已。你在别的文件中定义了一个变量(函数外),它默认就是全局的,在别的文件中extern声明一下照样能引用。

出0入0汤圆

发表于 2013-12-23 11:46:38 | 显示全部楼层
直接上程序你就看清楚了。
例如,在其他C文件中要用到LEDDP_buff[LEDDP_NUMBER],可以直接引用TreeOS_LEDDP_dynamic_B.h,因为LEDDP_NUMBER也要声明。
如果用到 LEDDP_char_blink_set ,既可以引用TreeOS_LEDDP_dynamic_B.h,也可以用extern ui8 LEDDP_char_blink_set来声明,效果是一样的。
在某个函数内定义的才是局部变量。
通常,当程序体量很大时,为了便于分清全局变量或局部变量,可以设定不同的书写规则。例如小写加下划线为全局变量,例如relay_status;头字母大写为局部变量,例如RelayStatus。
变量名也是一种注释,对程序的可读性很重要,要做到字义明确,一看就知道它的含义,不要怕长。

www.treeos.com.cn去下载一些例程来看看吧。

  1. /**************** (C) COPYRIGHT 2012  北京光轮电子科技有限公司******************

  2.         详情请登录:http://www.treeos.com.cn(论坛)、http://www.treeos.cn(官网)
  3.                     或 http://www.dpjwx.com(单片机网校)。

  4. ********************************************************************************

  5. 文件名称:TreeOS_LEDDP_dynamic_B.c
  6. 作者:林添孝
  7. 适用TreeOS:本软件适用于TreeOS v1.0实时操作系统。
  8. 移植时请注意标记 “//M/ ”,表示该处软件可能需要修改(Modify)。
  9. 学员若有疑问或建议,请发邮件到 treeos@sina.com 与我们联系。

  10. 版本:Ver 1.00, 2012
  11. 配置:缺省配置适用 GL210C51 v1 开发板。

  12. 功能:
  13. *LED数码管显示驱动程序,动态显示模式。
  14. *数码管个数1~8个
  15. *使用74HC574发送并行数据给各个LED数码管
  16. *数字、小数点可以控制是否闪烁,闪烁频率由LEDDP_BLINK_CIRCLE调整

  17. *LEDDP为LED digital pipe数码管的简写。

  18. 使用方法:
  19. 1、LEDDP_buff[LEDDP_NUMBER]为显示存储区;
  20. 2、直接刷新显示存储区的内容,即可显示出来;
  21. 3、有闪烁显示需求时,需在ScanInWhile()调用Scan_LEDDP(void);

  22. *B版刷新显存的任务放在中断中

  23. *******************************************************************************/

  24. /********includes**************************************************************/
  25. #include<reg52.h> //M/
  26. //#include<intrins.h>

  27. #include "TreeOS_LEDDP_dynamic_B.h"
  28. #include "TreeOS_hc574.h"  //M/
  29. #include "TreeOS_seg7_font.h"
  30. #include "TreeOS_mcu.h"


  31. /********全局变量**************************************************************/

  32. //显示数据缓冲区
  33. ui8 LEDDP_buff[LEDDP_NUMBER];  //注意显示顺序:从左[0]--->右[DIGNUM-1]

  34. //动态模式用到的变量
  35. ui8 LEDDP_scan_time_stamp=LEDDP_SCAN_CIRCLE;         //动态扫描时间戳
  36. ui8 LEDDP_prt=0; //动态扫描指针

  37. //字符闪烁用到的变量
  38. ui8 LEDDP_char_blink_set=0;         //字符闪烁设置
  39. ui8 LEDDP_dot_blink_set=0;         //小数点闪烁设置
  40. ui16 LEDDP_blink_time_stamp=LEDDP_BLINK_CIRCLE;         //闪烁时间戳
  41. enum SWITCH   LEDDP_blink_status=OFF; //闪烁显示状态

  42. /******************************************TreeOS Real-Time Operating System****
  43. Function Name:
  44. Description  : 数码管动态显示模式驱动程序
  45.                发送并行数据给数码管,并循环点亮其中一只,其它都灭掉
  46.                
  47. Input        : 数码管的数据LEDDP_buff[];
  48.                动态扫描指针: LEDDP_prt
  49. Output       :
  50. Return       :
  51. *******************************************************************************/
  52. void send_LEDDP_data(void)         
  53. {
  54. ui8 busval, tmp;
  55.    //必须先保护数据总线的数据!
  56.    busval=DATABUS;
  57.    tmp=LEDDP_buff[LEDDP_prt];

  58.    CLR_LEDDP_ALL_DIG();      //关闭全部数码管,否则会有余晖!
  59.    if(LEDDP_blink_status==OFF)         //闪烁显示“灭”周期
  60.      {
  61.           if(LEDDP_char_blink_set&(1<<LEDDP_prt)) tmp&=seg7_dot;   //清空,保留了小数点。
  62.           if(LEDDP_dot_blink_set&(1<<LEDDP_prt))  tmp&=~seg7_dot;  //清小数点。
  63.          }
  64.    SET_LEDDP_SEG(tmp);
  65.    // SET_LEDDP_SEG(LEDDP_buff[LEDDP_prt]); //设置段码数据
  66.    SET_LEDDP_DIG(LEDDP_prt); //点亮其中一只
  67.    LEDDP_prt++;                                 //动态扫描指针下移
  68.    if(LEDDP_prt>=LEDDP_NUMBER)        LEDDP_prt=0;

  69.    //恢复数据总线的数据
  70.    DATABUS=busval;
  71. }

  72. /********************************************************************************

  73. 文件名称:TreeOS_LEDDP_dynamic_B.h
  74. 作者:林添孝
  75. 适用TreeOS:本软件适用于TreeOS v1.0实时操作系统。
  76. 移植时请注意标记 “//M/ ”,表示该处软件可能需要修改(Modify)。
  77. 学员若有疑问或建议,请发邮件到 treeos@sina.com 与我们联系。
  78. oooooo欢迎童鞋们提出宝贵意见!oooooo

  79. 版本:Ver 1.00, 2012
  80. 配置:缺省配置适用 GL210C51 v1 开发板。


  81. 功能:
  82. *TreeOS_LEDDP_dynamic_B.c的配置文件

  83. /********防止冲突 prevent recursive inclusion**********************************/

  84. #ifndef _TREEOS_LEDDP_dynamic_B_H
  85. #define _TREEOS_LEDDP_dynamic_B_H

  86. /********includes**************************************************************/

  87. #include "TreeOS_typedef.h"
  88. /********全局变量声明**********************************************************/

  89. extern ui8 LEDDP_buff[LEDDP_NUMBER];  //注意显示顺序:从左[0]--->右[DIGNUM-1]
  90. extern ui8 LEDDP_scan_time_stamp;
  91. extern ui8 LEDDP_prt; //动态扫描指针

  92. //字符闪烁用到的变量
  93. extern ui8 LEDDP_char_blink_set;         //字符闪烁设置
  94. extern ui8 LEDDP_dot_blink_set;         //小数点闪烁设置
  95. extern ui16 LEDDP_blink_time_stamp;         //闪烁时间戳
  96. extern enum SWITCH   LEDDP_blink_status; //闪烁显示状态


  97. /********函数声明**************************************************************/
  98. void send_LEDDP_data(void);
  99. void iscan_LEDDP_dynamic(void);
  100. void LEDDP_init(void);
  101. void scan_LEDDP(void);

  102. #endif

  103. /***** (C) COPYRIGHT 2012  Beijing GuangLun Electronic Technology Co., Ltd.****/
复制代码

出0入0汤圆

发表于 2013-12-23 11:58:59 | 显示全部楼层
局部变量应该是分为函数内部的、函数外当前文件内部的。函数内部定义的其他函数不能使用,函数外文件内定义的可以在当前文件内的所有函数调用。
全局变量应该是不在函数内部声明的,调用范围在当前文件,其它文件内容要用的话必须在.h里面添加引用并#include "对应.h"
看使用范围来定什么是局部变量和全局变量。
函数内部的局部变量空间是动态分配的(除了静态变量),函数调用结束后就注销了!
函数外定义的变量都是固定分配的,MCU上电后一直占用!

出0入0汤圆

 楼主| 发表于 2013-12-23 12:16:18 | 显示全部楼层
shuipaopao 发表于 2013-12-23 11:01
1.h文件中声明的变量是全局变量,要加external 说明,局部变量都是在子程序中声明。有谁把子程序放在.h文件 ...

谢谢回复!

出0入0汤圆

 楼主| 发表于 2013-12-23 12:19:21 | 显示全部楼层
qlb1234 发表于 2013-12-23 11:24
Variable declarations are better placed in C files.

Accessing global(project scope, real global) va ...

谢谢回复

出0入0汤圆

 楼主| 发表于 2013-12-23 12:25:11 | 显示全部楼层
snower 发表于 2013-12-23 11:27
首先,没有 external 这个关键字,应该是 extern

1.假如现在系统中有多个.c文件和多个.h文件,一般变量声 ...

谢谢你的回复!

出0入0汤圆

 楼主| 发表于 2013-12-23 12:26:04 | 显示全部楼层
DevLabs 发表于 2013-12-23 11:34
1,一般声明在h文件中的都是全局变量,定义在模块对应的c文件里。2,#include不过是通过预处理器把声明放在 ...

谢谢回复!

出0入0汤圆

 楼主| 发表于 2013-12-23 12:27:08 | 显示全部楼层
1欧姆 发表于 2013-12-23 11:46
直接上程序你就看清楚了。
例如,在其他C文件中要用到LEDDP_buff[LEDDP_NUMBER],可以直接引用TreeOS_LEDDP ...

谢谢回复!

出0入0汤圆

 楼主| 发表于 2013-12-23 12:28:18 | 显示全部楼层
passage110 发表于 2013-12-23 11:58
局部变量应该是分为函数内部的、函数外当前文件内部的。函数内部定义的其他函数不能使用,函数外文件内定义 ...

谢谢你的回复

出0入0汤圆

 楼主| 发表于 2013-12-23 12:34:23 | 显示全部楼层
marshallemon 发表于 2013-12-23 10:30
区分开全局变量,模块级全局变量,局部变量就好了,每一个.C文件和其对应的.H文件称为一个模块,模块级的全 ...

请问这三种变量中,模块化的全局变量和全局变量有何区别?

出0入0汤圆

发表于 2013-12-23 13:26:50 | 显示全部楼层
static声明的变量只在当前文件内有效

出0入0汤圆

 楼主| 发表于 2013-12-23 14:29:19 | 显示全部楼层
hitlfba11 发表于 2013-12-23 13:26
static声明的变量只在当前文件内有效

好的,谢谢!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 23:32

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表