jhjkdz 发表于 2013-12-23 10:30:30

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

1.假如现在系统中有多个.c文件和多个.h文件,一般变量声明都是放在.h文件当中,那么这种变量属于局部变量吗?如果是,那全局变量又是在哪里定义的?
2.一个.c文件要调用其它.h文件的变量时,用#include “...h”和用关键字 external的区别?
新手求教。

shuipaopao 发表于 2013-12-23 11:01:50

本帖最后由 shuipaopao 于 2013-12-23 11:04 编辑

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

Let 发表于 2013-12-23 11:06:31

赚完钱走人

marshallemon 发表于 2013-12-23 10:30:31

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

qlb1234 发表于 2013-12-23 11:24:53

本帖最后由 qlb1234 于 2013-12-23 11:45 编辑

Variable declarations are better placed in C files.
char global_a;//This variable can be accessed by all the functions, as long as they "externed" it before like "extern char global_a;".
static char file_scope_b;//This variable can be accessed only by the functions later in this file and can never be "externed".
void func(void)
{
    ...
    char function_scope_c;//This variable can be accessed only by the lines below this line within this function.
    ....
}
Accessing global(project scope, real global) variables in another C file.
void foo(void)
{
    extern char global_a;
    a = 21;
}
H文件並非必要的存在。#include的作用,是將目標文件的內容,全數複製至本行位置。
所以欲使global_a很方便地在其它C文件中被訪問,而又懶得每次添加extern char global_a;,其中一竅門,便是編寫一H文件,在其中加入extern char global_a;,然後在每箇欲訪問其的C文件內包含(#include)這箇H文件。

snower 发表于 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

DevLabs 发表于 2013-12-23 11:34:58

1,一般声明在h文件中的都是全局变量,定义在模块对应的c文件里。2,#include不过是通过预处理器把声明放在当前文件中而已。你在别的文件中定义了一个变量(函数外),它默认就是全局的,在别的文件中extern声明一下照样能引用。

1欧姆 发表于 2013-12-23 11:46:38

直接上程序你就看清楚了。
例如,在其他C文件中要用到LEDDP_buff,可以直接引用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去下载一些例程来看看吧。

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

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

********************************************************************************

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

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

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

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

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

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

*******************************************************************************/

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

#include "TreeOS_LEDDP_dynamic_B.h"
#include "TreeOS_hc574.h"//M/
#include "TreeOS_seg7_font.h"
#include "TreeOS_mcu.h"


/********全局变量**************************************************************/

//显示数据缓冲区
ui8 LEDDP_buff;//注意显示顺序:从左--->右

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

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

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

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

   //恢复数据总线的数据
   DATABUS=busval;
}

/********************************************************************************

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

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


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

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

#ifndef _TREEOS_LEDDP_dynamic_B_H
#define _TREEOS_LEDDP_dynamic_B_H

/********includes**************************************************************/

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

extern ui8 LEDDP_buff;//注意显示顺序:从左--->右
extern ui8 LEDDP_scan_time_stamp;
extern ui8 LEDDP_prt; //动态扫描指针

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


/********函数声明**************************************************************/
void send_LEDDP_data(void);
void iscan_LEDDP_dynamic(void);
void LEDDP_init(void);
void scan_LEDDP(void);

#endif

/***** (C) COPYRIGHT 2012Beijing GuangLun Electronic Technology Co., Ltd.****/

passage110 发表于 2013-12-23 11:58:59

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

jhjkdz 发表于 2013-12-23 12:16:18

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

谢谢回复!

jhjkdz 发表于 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 ...

谢谢回复

jhjkdz 发表于 2013-12-23 12:25:11

snower 发表于 2013-12-23 11:27
首先,没有 external 这个关键字,应该是 extern

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

谢谢你的回复!

jhjkdz 发表于 2013-12-23 12:26:04

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

谢谢回复!

jhjkdz 发表于 2013-12-23 12:27:08

1欧姆 发表于 2013-12-23 11:46
直接上程序你就看清楚了。
例如,在其他C文件中要用到LEDDP_buff,可以直接引用TreeOS_LEDDP ...

谢谢回复!

jhjkdz 发表于 2013-12-23 12:28:18

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

谢谢你的回复

jhjkdz 发表于 2013-12-23 12:34:23

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

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

hitlfba11 发表于 2013-12-23 13:26:50

static声明的变量只在当前文件内有效

jhjkdz 发表于 2013-12-23 14:29:19

hitlfba11 发表于 2013-12-23 13:26
static声明的变量只在当前文件内有效

好的,谢谢!
页: [1]
查看完整版本: 在多个.c和多个.h文件当中,如何区别全局变量和局部变量