当前位置: 首页 > ops >正文

标识符和预处理 day12

十一:标识符作用域和可见性规则

一:变量 (标识符)作用域:

​ 局部作用域 //{ }所在的范围就是局部作用域

​ 全局作用域(静态区) //不在任何一个{ }范围内

二:可见性:

​ 标识符的可见性的规则:

​ 1.先定义,后使用

​ 2.同一作用域中,不能有同名标识符

​ 3.在不同的作用域,同名标识符,相互之间没有影响

​ 4.如果是不同的作用域,但是作用域之间存在嵌套关系,即内层的作用域的同名标识符,会屏蔽外层的作用域的同名标识符(就近原则)

int a = 50;//全局变量也要遵守就近原则void test_int()
{int a = 20;printf("3 a = %d\n",a);//不同作用域
}int main(int argc, const char *argv[])
{int a = 10;printf("1 a = %d\n",a);{int a = 30;printf("2 a = %d\n",a);//嵌套同名作用域,a = 30,就近原则;}return 0;
}

三:auto

auto int a; //auto----表示说这是一个自动变量

​ //意味着这个变量的存储空间是开在栈区

​ //自动申请,自动释放般局部变量

​ //默认都是auto类别的,所以一般都不写

四:static

static int a; //static修饰局部变量

​ //表示将该变量存储空间 开在全局区 (静态区)

​ //全局区的变量量—生命周期和(auto)局部变量的生命周期不一样

五:生命周期

auto的局部变量的生命周期:是从定义处开始存在,到作用域结束,此时销毁,这段时间是它生命周期

static的变量(静态变量)和全局变量的生命周期:从程序运行开始到程序结束

​ 1.只会被初始化一次

​ 2.变量具有继承性

​ 3.不能用变量初始化,只能用常量初始化

​ 4.全局变量也不能用变量初始化

#include<stdio.h>int c = 5;
int a = c;//4.全局变量也不能用变量初始化void test_int(void)
{int b = 30;static int a = b;//不能用变量初始化,只能用常量初始化static int a = 30//把上两个注释删除后,程序成功编译,此时static int a = 30;只在第一次调用时执行初始化,之后的调用不再初始化!所以静态变量 a 初始为 30,之后每次调用都会自增并打印a++;printf("2 a = %d\n",a);return;
}int main(int argc, const char *argv[])
{int a = 10;printf("1 a = %d\n",a);int i = 0;for(i=0;i<10;i++)test_int();return 0;
}

六:register寄存器

register int a;//作用:表示’建议‘将变量a的空间放在寄存器中—以提高访问效率,

​ //最终有没有放进寄存器,看系统调度。

	register int a = 10;printf("1 &a = *p\n",a);//register修饰的变量 不能& 取地址

七:extern外部修饰

extern int a //表示变量a不在当前文件,可能在存在于别的文件中

​ //应用场景多个文件的场合

​ //也可以修饰函数

​ 一般用在函数声明中exterr int add(int)

#include<stdio.h>extern int add(int a,int b);
extern int sub(int a,int b);
extern int mul(int a,int b);
extern int div(int a,int b);//函数声明int main(int argc, const char *argv[])
{int a,b;scanf("%d%d",&a,&b);printf("add = %d\n",add(a,b));printf("sub = %d\n",sub(a,b));printf("mul = %d\n",mul(a,b));printf("div = %d\n",div(a,b));return 0;
}eg:gcc cal.c main.c		//编译两个文件

注意:1.修饰的变量—要求是全局变量

​ 2.修饰函数----一般用在函数声明中

八:static修饰问题

static限定修饰全局变量和函数,只能用于本文件中

static修饰局部变量 //是把局部变量存放在静态区–延长了整个程序生命周期

​ 修饰全局变量 //将全局变量的作用域,限定到本文件—别的文件不能引用(不能通过extern访问)

​ //1.保护数据 2.防止命名冲突

​ 修饰函数 //和全局变量的作用一样

static int sub(int a,int b)//此时main函数中,extern无法引用
{return a-b;
}

面试题:你知道static吗,介绍一下static

​ 答:是一个存储类别关键字,可以来修饰变量:1.局部变量,2.全局变量,(—解释1和2),也可以修饰函数,和修饰全局变量的作用一样。之后在举例说明

十二:预处理命令

一:各个阶段

​ 预处理 将c程序中 预处理 命令执行 得到一个纯的c程序文件

​ 编译 将预处理之后的c源程序文件 处理成汇编代码

​ 汇编 将汇编代码翻译成机器代码 01010

​ 链接 将我们写的代码和用到的别人写的代码(二进制形式)

​ 链接到一起生成最终的可执行文件

gcc -E test.c -o test.i//预处理
gcc -S test.i -o test.s//编译
gcc -c test.c -o test.o//汇编
gcc test.o -o test.out//链接eg:test.c  test.i  test.o  test.out  test.s./test.out //运行

二:宏定义

1.用一个指定的标识符子(即名字)来代表一个字符串

#define 标识符		字符串
#define 宏名		 宏值

说明:1.宏名-----自己定义一个标识符,符合标识符命名规则,一般建议写成大写与普通变量名区分

​ 2.宏值-------表示宏名要代表的值,它本身只是一个文本字符串 (文本信息),与C语言中字符串常量不是一个概念文

​ 3.预处理阶段------做的工作: 文本的原样替换用宏值替换宏名

​ 4.宏定义 最后不写分号,除非需要

​ 5.出现在" "的字符串中与宏名同名的标识符不会被替换、

​ 6.宏的作用域 //从定义出开始,到文件结束处

​ 7.宏函数不是函数,只是一个带参宏, 参数不会做类型检测,是文本原样替换 使用时,是用宏值代替宏名

#include<stdio.h>
#define N 20;int main(int argc, const char *argv[])
{int n = N;printf("n =  %d\n",n);return 0;
}

三:带参数的宏定义

1.能加括号就加括号

#include<stdio.h>
#define ADD(a,b) (a)+(b)
#define MUL(a,b) (a)*(b)int main(int argc, const char *argv[])
{printf("result = %d\n",MUL(1+3,2+4));return 0;
}

四:取消宏定义

#define MAX(a,b) a>b?a:b
#undef MAX(a,b) a>b?a:b

五:文件包含

#include"文件名" //默认在当前位置下寻找,若没有,则区系统路径寻找

或#include<文件名> //在系统路径下寻找

将所包含的文件的内容,最终放到指令所在的文件 //本质:还是文本替换

文件名----格式没有要求 //C语言中,头文件一般是.h结尾

六:条件编译

形式一:如果定义了标识符 则将程序段1替换到最终的代码中,如果没有定义了标识符 则将 程序段2替换到终的代码中

#ifdef标识符程序段1
#else标识符程序段2
#endif------------------------------------------       
#define N
int main(int argc, const char *argv[])
{
#ifdef Nprintf("yes\n");
#else printf("no\n");
#endifreturn 0;
}

形式二:逻辑与形式一正好相反

#ifndef标识符程序段1
#else标识符程序段2
#endif 

形式三:表达式为真则将程序段1替换到最终的代码中,表达式为假则将程序段2替换到最终的代码中,

#if	表达式(逻辑判断)程序段1
#else程序段2
#endif

条件编译可以解决头文件重复的问题

main.c文件
#include<stdio.h>
#include"add.h"
#include"add.h"//会二次定义,但是有条件编译防止问题int main(int argc, const char *argv[])
{int a = 1;int b = 2; printf("add = %d\n",add(a,b));return 0;
}
-------------------------------
add.c文件
int add(int a,int b)
{return a+b;
}
-----------------
add.h文件
#ifndef _ADD_H_//当第一次#include ,定义了add
#define _ADD_H_//当第二次#include时,由于已经定义了一次,所以不会在第二次定义//条件编译防止头文件重复的功能
int add(int a,int b);#endif
http://www.xdnf.cn/news/13525.html

相关文章:

  • 6.10[A]BB84 量子
  • 一般增长率
  • Kubernetes 从入门到精通-ReplicaSet控制器
  • 超级神冈探测器2025.6.11
  • Java多线程通信核心机制详解
  • 通过共享内存在多程序之间实现数据通信
  • Python实例题:Python计算泛函分析
  • Linux操作系统故障排查案例实战
  • 南京师范大学 AM:焦耳加热 “点亮” 高效析氢新路径
  • Amazon Linux 2023 系统上 Radius 部署文档
  • 三维自动光学检测-3D扫描扇叶尺寸检测设备-中科米堆
  • 运维之十个问题--6
  • URL末尾加“/“与不加“/“区别
  • 【Dv3Admin】系统视图消息中心API文件解析
  • 与算法相关的一些数学物理理论知识
  • mysql DQL(javaweb第七天)
  • 2025年春季学期《算法分析与设计》练习15
  • Docker快速构建并启动Springboot程序,快速发布和上线/
  • OM6629 是一款针对蓝牙低功耗和专有 2.4GHz 系统级芯片(SoC)解决方案
  • 汉诺塔 (easy)
  • 根据 LiDAR 株高数据计算植被生物量
  • Koji构建系统宏定义注入与Tag体系解析
  • GEO行业中的STREAM框架解析:内容一致性得分(A)如何实现全渠道品牌信息的协同与统一
  • LangGraph基础知识(Reducer/MessageGraph)(二)
  • 机器学习赋能的智能光子学器件系统研究与应用
  • 开疆智能ModbusTCP转Canopen网关连接AGV地标传感器
  • HGAdmin无法连接本地数据库解决方式(APP)
  • Linux操作系统基线检查与安全加固概述
  • ZYNQ学习记录FPGA(三)状态机
  • 梯度范数的作用