嵌入式八股文篇——P1 关键字篇
嵌入式八股文篇--P1 关键字篇
目录
嵌入式八股文篇--P1 关键字篇
1. Continue
2. Break
3. Return
4. Goto
5. Volatile(编译优化阶段)
6.Struct(结构体) (C和C++区别,求结构体大小,使用的注意事项)
7.class和struct的区别?
8.Union(联合体)
8.1.联合体union和结构体struct的区别:
8.2.联合体一般可以用来判断大小端问题:
8.3.大小端转换问题:
8.4.计算占用空间大小问题:
9.Enum
10.Typedef
11.Const (C中的变量:局部,函数形成,返回值,指针,typedef的区别,数组大小定义,case C++:常函数,常对象)
12.Extern(链接阶段)
13.Register
14.Auto
15.Static (c语言:变量、函数 C++:类中变量、类中静态成员函数)
16.Swicth case
17.Do while
18.Sizeof
19.New/malloc delete/free(指明大小,返回值,初始化)
20.左值和右值是什么?
21. 什么是短路求值
22.++a和a++区别
23.局部变量能不能和全局变量重名?
24. gets和scanf函数的区别(空格,输入类型,返回值)
25. C语言编译过程中,volatile关键字和extern关键字分别在哪个阶段起作用?
26. Printf()函数的返回值
27.C语言中不能用来表示整常数的进制是二进制
28.char *str1 = “hello”和char str2[] = “hello”
1. Continue
continue
仅用于循环语句,作用是跳过本次循环剩余语句,直接进入下一次循环条件判断(不终止整个循环),核心是 “局部跳过当前轮,循环整体仍继续”。
总结:跳本轮回判(跳过本次循环,进入下一轮判断)
2. Break
break
仅用于循环(for/while/do-while)或 switch 语句,作用是强制跳出最近包含它的那一层结构:在循环中,终止当前循环的所有后续迭代;在 switch-case 中,终止当前 case 的执行并跳出整个 switch。若结构嵌套(如 for 循环内有 switch),break 仅影响直接包含它的内层结构,不影响外层。需特别注意:switch 中若缺少 break,会从匹配的 case 开始 “穿透执行” 所有后续分支(包括 default),直到遇到 break 或 switch 结束。
与 continue 对比:break 是 “终止本层结构”,continue 是 “跳过本次循环”。
总结:破层终止(破坏当前层级结构并终止其执行)
3. Return
return
是函数体专用的关键字,作用是立即终止当前函数的所有执行(包括函数内的循环、分支等),退出函数并返回至调用处;若函数为非 void
类型,需携带匹配类型的返回值传递给调用者,void
类型则可直接用 return;
实现提前退出。
总结:退函返值(退出函数并返回值)
4. Goto
goto
是用于当前函数内的无条件跳转语句,可直接跳转到预定义的标签(格式为标签名:
)处执行,无需遵循正常代码顺序。主要用途是跳出多层循环或集中处理错误,但滥用会导致逻辑混乱,且不能跨函数跳转。
总结:函数内跳标签(慎用于多层循环跳出)
5. Volatile(编译优化阶段)
volatile 作用于编译优化阶段,用于修饰可能被当前代码外因素(如中断、多线程、硬件寄存器)修改的变量,强制编译器每次使用变量时都从内存重新读取,而非使用寄存器缓存的旧值,避免数据失效。
总结:强读内存禁优化
6.Struct(结构体) (C和C++区别,求结构体大小,使用的注意事项)
struct
(结构体)在 C 与 C++ 中差异显著:C 语言结构体仅能包含数据成员,不可有函数、不支持继承,使用时需加struct
或通过typedef
取别名,成员默认 public 且不可初始化,空结构体大小为 0;C++ 结构体可包含函数、支持继承,可直接用结构体名定义变量,支持权限控制(public/private 等),允许成员初始化,空结构体大小为 1。计算结构体大小时需遵循字节对齐规则(总大小为最大成员类型字节数的整数倍,成员偏移量为自身类型字节数的整数倍)。
总结:C 简 C++ 强,大小看对齐
7.class和struct的区别?
class 与 struct 的核心区别集中在权限与功能场景:从访问权限看,class 成员默认 private(仅类内可访问),struct 默认 public(外部可直接访问);从继承权限看,class 默认 private 继承(子类无法直接访问父类成员),struct 默认 public 继承(子类可直接访问父类 public 成员);从功能场景看,class 更侧重封装 “对象实现”(隐藏内部逻辑),struct 更侧重定义 “数据结构”(暴露数据),且 class 可用于定义模板,struct 不支持此功能。
总结:权默异(class 私 struct 公),功能别(class 能模板 struct 不能)
8.Union(联合体)
8.1.联合体union和结构体struct的区别:
union(联合体)与 struct(结构体)的核心区别在于内存分配方式:联合体的所有成员共享同一块内存空间,修改任一成员会直接接影响其他成员;而结构体的成员各自占独立独立内存,总空间是各成员内存的叠加(需考虑字节对齐),成员间数据互不干扰。
总结:联共内(成员共享内存),结叠存(成员内存叠加)
8.2.联合体一般可以用来判断大小端问题:
联合体是判断大小端的常用工具:利用其成员共享内存的特性,通过多字节数据在内存中的存储顺序区分 —— 大端字节序中高字节存低地址、低字节存高地址;小端字节序中低字节存低地址、高字节存高地址。
示例中,联合体my
的short t
与char b[2]
共享内存,当t=0X0102
时:若b[0]=0x01
且b[1]=0x02
,为大端;若b[0]=0x02
且b[1]=0x01
,则为小端。
总结:联共内存判端序(高存低为大,低存低为小)
8.3.大小端转换问题:
大小端转换主要通过位运算(与运算 + 位移运算) 实现,核心思路是将数据各字节的存储位置按需求互换。以 32 位数据为例,需将原本 0-7 位(最低字节)移到 24-31 位(最高字节)、8-15 位移到 16-23 位、16-23 位移到 8-15 位、24-31 位(最高字节)移到 0-7 位。
如代码所示,先通过&
运算提取各字节(如value & 0x000000ff
提取 0-7 位),再用<<
/>>
将其移到目标位置,最后用|
运算合并各字节,完成 32 位数据的大小端转换。
//32位大小端交换
int swap(int value)
{
value=((value & 0x000000ff)<<24)|
((value & 0x0000ff00)<<8)|
((value & 0x00ff0000)>>8)|
((value & 0xff000000)>>24);
return value;
}
8.4.计算占用空间大小问题:
对于不同位的操作系统,个别数据类型数据大小不一样,
Long 和unsigned long在32位中是4个字节
在64位中是8个字节
计算联合体(union)和结构体(struct)的占用空间需遵循字节对齐规则,核心要点如下:
- 基础规则:
-
- 总大小必须是成员中最大类型字节数的整数倍
- 每个成员的偏移量(距起始地址)必须是自身类型字节数的整数倍
- 联合体计算:因所有成员共享内存,大小需同时满足:①能容纳最大成员(含数组总大小);②是最大成员类型字节数的整数倍。例如
union {double i; int k[5];}
中,int[5]
占 20 字节,double
为 8 字节,故总大小为 24(8 的 3 倍,且≥20)。 - 结构体计算:成员内存叠加,需注意:①嵌套联合体时,其起始偏移量需符合自身最大成员类型的对齐要求;②最终总大小是结构体中最大类型(含嵌套类型)字节数的整数倍。例如含
int
(4 字节)、24 字节联合体(最大成员 8 字节)、double
(8 字节)的结构体,总大小为 40(8 的 5 倍)。
总结:对齐看最大,联取容大值,结叠算偏移
9.Enum
enum
(枚举)是用于定义离散常量集合的类型,内部常量默认从 0 开始依次自增(可手动指定初始值打破自增序列),为离散值提供语义化名称,增强代码可读性。例如enum Week {Mon, Tue, Wed};
中,Mon=0、Tue=1、Wed=2。
总结:枚举常量自增(默认从 0 起,可手动指定)
10.Typedef
typedef
是编译期关键字,用于给已有类型起别名,具有类型检查功能,可简化数组、指针、结构体等复杂类型的使用,且在其作用域内有效,不能在函数内定义;与 #define
(预处理指令,仅做字符串替换,无类型检查)的核心区别在于:定义指针时,typedef
能保证所有变量均为指针类型(如 typedef int* myptr; myptr a,b;
中 a
和 b
都是指针),而 #define
可能导致部分变量类型不符合预期(如 #define myptr int*; myptr a,b;
中 b
是 int 类型)。
总结:类型别名(编译检查,指针定义无歧义)
11.Const (C中的变量:局部,函数形成,返回值,指针,typedef的区别,数组大小定义,case C++:常函数,常对象)
const
是用于定义 “只读实体” 的关键字,在 C 和 C++ 中功能各有侧重:在 C 中,可修饰变量(表值不可改)、函数参数(表函数内不可改参数)、函数返回值(表返回内容不可改),修饰指针时分 “常量指针”(内容不可改)、“指针常量”(地址不可改)、“完全只读指针”(地址和内容均不可改);需注意 C 中 const
变量非编译期常量,不能用于定义数组大小或 switch case
常量,推荐用 #define
定义此类常量。在 C++ 中,除兼容 C 的功能外,还可修饰 “常函数”(类成员函数,仅读类成员不修改)和 “常对象”(仅调用常函数)。存储上,局部 const
变量存栈(C 中可间接修改),已初始化的全局 const
变量存只读数据段(不可修改)。
总结:定义只读实体(C 限变量指针,C++ 加常函数对象)
12.Extern(链接阶段)
extern
是作用于链接阶段的关键字,核心用于跨文件引用实体:一是声明外部变量(告知编译器变量在其他文件已定义并分配内存,本文件仅使用,不可初始化,且全局变量不能定义在头文件,避免多文件包含报 “multiple define” 错误);二是声明外部函数(告知编译器函数在其他文件定义,本文件可调用);此外,extern "C"
专门用于 C++ 中按 C 语言规则编译代码,解决 C++ 名称修饰导致的跨语言调用链接失败问题。
总结:链接声明外部(变量函数跨文件,C++ 用 "C" 调 C)
13.Register
register
是向编译器发起的 “建议性声明”,希望将局部整数类型变量存储到 CPU 寄存器中(利用寄存器高速访问特性提升效率),但编译器可根据寄存器资源情况决定是否采纳;需注意,register
不可修饰浮点数、数组等类型,也不能对被修饰变量执行取地址操作(&)。
总结:建议存寄存器(限局部整数,禁取地址)
14.Auto
auto
是局部变量的默认存储类型(通常可省略),表示 “自动存储期”—— 变量存储在栈中,函数执行结束后会自动销毁,仅在定义它的局部作用域内有效,无法修饰全局变量或静态变量。
总结:局部默认存栈(自动销毁,限局部域)
15.Static (c语言:变量、函数 C++:类中变量、类中静态成员函数)
static
关键字在 C 和 C++ 中功能丰富,核心是限定作用域与延长生命周期:
C 语言中
- 静态变量:
-
- 静态局部变量:仅在函数内可见,生命周期与程序一致(函数退出不销毁),仅初始化一次(保留上次值),存储在数据段 /.bss 段。
- 静态全局变量:仅在本文件内可见(其他文件无法通过
extern
访问),生命周期与程序一致,避免全局命名冲突。
- 静态函数:仅在本源文件内可调用,其他文件可定义同名函数,实现 “文件私有”。
C++ 扩展(类中)
- 静态成员变量:所有对象共享同一块内存,不占类空间,需在类外单独定义(类内仅声明,不可在构造函数中初始化)。
- 静态成员函数:属于类而非对象,无
this
指针,仅能访问静态成员,不能访问非静态成员(面试高频考点)。
总结:静存久,域受限;类静共,无 this
16.Swicth case
switch case
是多分支条件判断结构,核心规则有三:①表达式结果必须是整数 / 字符类型(不可为浮点数或字符串);②case 后必须是常量(不可为变量或字符串,字符因本质是整数可使用);③若无 break,会从匹配 case 开始 “穿透执行” 所有后续分支(直至 break 或结构结束)。
总结:整表常量判,break 防穿透
17.Do while
do while
是一种循环结构,核心逻辑是 “先执行循环体,再判断条件”—— 无论条件是否成立,循环体至少会执行一次,仅当条件为假时才退出循环,适用于需先执行再判断的场景(如输入验证)。
总结:先执行再判(循环体至少一次)
18.Sizeof
sizeof
是编译期关键字,核心用于计算变量 / 类型的内存占用大小,关键特性与差异如下:
- 与
strlen
区别:sizeof
算内存大小(含字符串\0
)、编译期计算、是关键字;strlen
算字符串有效长度(不含\0
)、运行期计算、是函数。 - 特殊计算:32 位机下指针大小恒为 4 字节;引用大小与对应类型一致;数组大小 = 类型字节数 × 元素数(如
int[5]
为 20 字节);sizeof(a++)
不执行表达式(a
值不变)。 - 特殊值:
sizeof("\0")
为 2(含两个\0
),sizeof('\0')
为 4(字符按int
存储),sizeof(void)
出错或为 1;自定义宏mysizeof
可通过地址差模拟其功能。
总结:编译算内存(含 \0,不执行表达式,指针 32 位恒 4)
19.New/malloc delete/free(指明大小,返回值,初始化)
new/delete
与 malloc/free
均用于动态内存管理,但核心差异显著:
- 性质:
new/delete
是 C++ 运算符,malloc/free
是 C 标准库函数。 - 功能:
new
申请内存后自动调用构造函数初始化,delete
先调用析构函数再释放内存;malloc
仅申请内存(需显式指定大小),free
仅释放内存,均不处理构造 / 析构。 - 使用:
new
返回对应类型指针(无需强转),malloc
返回void*
(需显式强转)。
总结:new 带构造免强转,malloc 仅申请需大小
20.左值和右值是什么?
左值和右值是 C/C++ 中用于区分表达式或变量 “可被操作特性” 的概念,核心差异在于是否可被修改、能否放在赋值运算符左侧:
- 左值:本质是 “有明确内存地址、可被修改” 的实体,能出现在赋值运算符左侧(也可出现在右侧)。比如普通变量(
int a
)、数组元素(arr[0]
)等,其值可通过赋值改变;但需注意,数组名是 “常量左值”,虽有内存地址,却不可被修改(如str++
或str = new char[5]
均报错)。 - 右值:本质是 “临时结果、无持久内存地址、不可被修改” 的实体,仅能出现在赋值运算符右侧。比如字面量(
10
、"abc"
)、表达式结果(a + b
)、后置自增(a++
,因其返回的是自增前的临时值)等,无法作为赋值对象(如i++ = 5
报错)。
核心规则:左值可作右值,右值不能作左值;特殊左值(如数组名)虽有地址,但不可修改。
总结:左值可改放左边,右值只读放右边(数组名是特殊左值,不可改)
21. 什么是短路求值
短路求值是逻辑运算符(||
逻辑或、&&
逻辑与)的核心特性:在判断表达式结果时,若通过前面的部分已能确定最终结果,就不再执行后续部分,直接返回结果,以此提升效率。具体规则与示例如下:
1. 逻辑或(||
):一真则真,遇真即停
只要左侧表达式为 “真”,就无需判断右侧表达式,直接返回 “真”;仅当左侧为 “假” 时,才执行右侧表达式进一步判断。
- 示例
a>0 || b++>2
:左侧a>0
(2>0
)为真,直接确定整体为真,右侧b++
未执行,故b
仍为 3。 - 而
a<0 || b++>2
:左侧a<0
(2<0
)为假,需执行右侧b++
,b
从 3 变为 4,最终整体为真。
2. 逻辑与(&&
):一假则假,遇假即停
只要左侧表达式为 “假”,就无需判断右侧表达式,直接返回 “假”;仅当左侧为 “真” 时,才执行右侧表达式进一步判断。
- 示例
a>0 && b++>2
:左侧a>0
为真,需执行右侧b++
,b
从 4 变为 5,最终整体为真。 - 而
a<0 && b++>2
:左侧a<0
为假,直接确定整体为假,右侧b++
未执行,b
仍为 5。
总结:|| 遇真停,&& 遇假停(后续表达式不执行)
22.++a和a++区别
++a
(前置自增)与 a++
(后置自增)的核心区别在于自增操作的执行时机、返回值类型及效率,具体差异如下:
1. 执行时机与返回值:核心差异
两者最终都会让 a
的值 + 1,但 “何时 + 1” 和 “返回什么值参与后续运算” 完全不同:
- a++(后置自增):先取值,后自增步骤:①先将
a
当前的值存入临时变量(返回的是自增前的 “旧值”);②再对a
本身执行 + 1 操作;③后续运算使用的是临时变量中的 “旧值”。例:int a=1; int b=a++;
→ 先将a=1
存入临时变量给b
(故b=1
),再让a
自增为 2。 - ++a(前置自增):先自增,后取值步骤:①先对
a
本身执行 + 1 操作;②直接返回a
的引用(无需临时变量,返回的是自增后的 “新值”);③后续运算使用的是a
自增后的 “新值”。例:int a=1; int b=++a;
→ 先让a
自增为 2,再将a=2
直接给b
(故b=2
)。
2. 效率差异:前置自增更高
a++
需额外开辟临时变量存储自增前的旧值,运算结束后还要释放临时空间,存在额外开销。++a
直接操作原变量并返回引用,无需临时变量,效率更高。(尤其在循环(如for
循环)或高频调用场景中,++a
的效率优势更明显。)
3. 复杂运算示例:结合返回值特性分析
所有运算均基于 “返回值” 进行,需明确两者返回的是 “旧值” 还是 “新值引用”:例:int i=1; printf("%d\n", ++i / i--);
- 第一步:
++i
先执行 →i
自增为 2,返回i
的引用(此时引用指向i=2
)。 - 第二步:
i--
执行 → 先将i=2
存入临时变量(返回旧值 2),再让i
自减为 1(此时++i
的引用指向i=1
)。 - 第三步:运算
++i
的返回值(1) /i--
的返回值(2) → 1/2=0(整数除法),最终输出 0。
总结:a++ 先值后增(需临时变量,效率低),++a 先增后值(无临时变量,效率高)
23.局部变量能不能和全局变量重名?
局部变量与全局变量可以重名,但会触发 “局部变量屏蔽全局变量” 的规则 —— 在局部变量的作用域内(如函数、代码块),代码默认操作的是局部变量,全局变量会被 “隐藏”,无法直接访问。
若需在局部作用域中使用被屏蔽的全局变量,可通过 extern
关键字声明该变量为 “外部全局变量”,明确指定使用全局版本。
示例如下:
#include <stdio.h>
int a = 1; // 全局变量avoid test() {int a = 2; // 局部变量a(与全局变量重名)printf("局部变量a:%d\n", a); // 默认操作局部变量,输出2// 用extern声明,显式使用全局变量{extern int a; printf("全局变量a:%d\n", a); // 输出1}
}int main() {test();return 0;
}
总结:可重名,局部屏蔽全局;用 extern 显式访全局
24. gets和scanf函数的区别(空格,输入类型,返回值)
gets
与 scanf
均为输入函数,但在处理方式、适用场景和返回值上差异显著,核心区别如下:
- 空格处理:
-
gets
会完整读取一行输入(包括空格),直到遇到换行符(\n
)才停止,且会自动丢弃换行符。scanf
遇空格、制表符或换行符时默认视为输入分隔符,会停止当前变量的输入(除非用格式控制符如%[^\n]
特殊处理)。
- 输入类型:
-
gets
仅用于读取字符串(char*
),功能单一。scanf
是格式化输入函数,可通过格式符(%d
、%f
、%s
等)读取整数、浮点数、字符串等多种基础类型。
- 返回值:
-
gets
返回char*
指针:成功时返回输入字符串的地址,失败(如读入错误)时返回NULL
。scanf
返回int
整数:表示成功赋值的变量个数,遇到文件结尾时返回EOF
(通常为-1
)。
示例对比:
char str1[20], str2[20];
gets(str1); // 输入 "hello world",str1 会存储完整字符串(含空格)
scanf("%s", str2); // 输入 "hello world",str2 仅存储 "hello"(遇空格停止)
总结:gets 读整行含空格(仅字符串),scanf 遇空格停(多类型),返回值类型不同
25. C语言编译过程中,volatile关键字和extern关键字分别在哪个阶段起作用?
在 C 语言编译过程中,volatile
和 extern
关键字的作用阶段不同:
volatile
:作用于编译阶段。它告诉编译器,被修饰的变量可能被意外修改(如硬件中断、多线程等),禁止编译器对该变量进行优化(如缓存变量值到寄存器、省略重复读取等),确保每次访问都直接从内存中读取最新值。extern
:作用于链接阶段。它用于声明外部变量或函数,告知编译器 “该实体在其他文件中定义”,在链接时由链接器根据声明找到对应的定义并完成地址关联,实现跨文件引用。
总结:volatile 防编译优化(编译期),extern 助跨文件链接(链接期)
26. Printf()函数的返回值
printf()
函数的返回值是成功输出的字符总数(包括数字、字母、空格、换行符 \n
等所有输出的字符),若输出失败则返回负数。
具体示例解析:
printf("%d\n", 241);
输出内容为"241\n"
,包含 3 个数字字符 + 1 个换行符\n
,共 4 个字符,故返回值为 4。printf("%d\n", printf("%d", 241));
-
- 内层
printf("%d", 241)
输出"241"
(3 个字符),返回值为 3。 - 外层
printf
输出内层返回的3
加换行符\n
,即"3\n"
(2 个字符),但整体输出结果为"2413\n"
,外层函数返回值为 2。 - 最终屏幕显示
"2413"
(换行被包含在输出中)。
- 内层
printf("%d\n", printf("%d\n", 241));
-
- 内层
printf("%d\n", 241)
输出"241\n"
(4 个字符),返回值为 4。 - 外层
printf
输出4
加换行符,即"4\n"
,整体输出为"241\n4\n"
,外层返回值为 2。 - 最终屏幕显示
"241"
换行后再显示"4"
。
- 内层
总结:返回输出字符总数(含所有符号和控制字符)
27.C语言中不能用来表示整常数的进制是二进制
在 C 语言中,整常数的表示仅支持十进制、八进制、十六进制三种进制,不支持二进制直接表示,具体规则如下:
- 十进制:默认形式,由数字
0-9
组成,不能以0
开头(除非数值本身是0
)。例:123
、-45
、0
。 - 八进制:以数字
0
开头,后续由0-7
组成。例:012
(对应十进制的10
)、077
(对应十进制的63
)。 - 十六进制:以
0x
或0X
开头,后续由0-9
、a-f
或A-F
组成。例:0x1A
(对应十进制的26
)、0XFF
(对应十进制的255
)。
若需使用二进制数值,需通过其他进制间接转换(如将二进制 1101
转为十进制 13
、八进制 015
或十六进制 0xD
后使用),或借助 C99 及后续标准中的 %b
格式符(部分编译器支持,非标准),但无法直接以二进制形式定义整常数。
总结:C 语言整常数无二进制表示,仅支持十进制、八进制、十六进制
28.char *str1 = “hello”和char str2[] = “hello”
char *str1 = "hello"
与 char str2[] = "hello"
是 C 语言中字符串两种常见定义方式,核心区别体现在存储位置、可修改性及变量性质上,具体差异如下:
1. 存储位置与内存性质
char str2[] = "hello"
(字符数组):字符串"hello"
被存储在栈区(局部数组)或数据段(全局数组),数组会分配独立内存空间(长度为 6,含终止符\0
),内容是字符串的副本。char *str1 = "hello"
(字符指针):字符串"hello"
被存储在只读数据段(常量区),指针str1
仅在栈区存储该常量字符串的首地址,本身不存储字符串内容。
2. 可修改性
- 字符数组
str2
:
-
- 数组名是常量指针(地址不可变),不能执行
str2++
等修改地址的操作。 - 但数组元素(内存内容)可修改,如
str2[0] = 'W'
是合法的(修改栈 / 数据段的副本)。
- 数组名是常量指针(地址不可变),不能执行
- 字符指针
str1
:
-
- 指针本身是变量,可修改指向的地址,如
str1 = "world"
是合法的(指向新的常量字符串)。 - 但指向的内容(只读数据段的常量)不可修改,如
*str1 = 'w'
会触发段错误(写入只读内存)。
- 指针本身是变量,可修改指向的地址,如
3. 本质区别总结
特性 |
|
|
变量性质 | 数组(分配独立内存存储内容) | 指针(仅存储常量字符串地址) |
地址可改性 | 不可改(数组名是常量指针) | 可改(指针可指向新地址) |
内容可改性 | 可改(修改数组内的副本) | 不可改(指向只读常量区) |
存储区域 | 栈区 / 数据段(可写) | 指针在栈区,内容在只读数据段 |
简言之:数组存副本(内容可改,地址不可改),指针存地址(地址可改,内容不可改)。
29. 局部变量和全局变量同名的时候如何使用全局变量
当局部变量与全局变量同名时,若要在局部作用域中使用全局变量,最直接的方式是通过 extern
关键字显式声明,明确指定引用全局版本。具体用法如下:
#include <stdio.h>int a = 10; // 全局变量int main() {int a = 20; // 局部变量(与全局变量同名)// 默认使用局部变量printf("局部变量 a: %d\n", a); // 输出 20// 使用 extern 声明,显式引用全局变量{extern int a; // 声明此处使用全局变量 aprintf("全局变量 a: %d\n", a); // 输出 10}return 0;
}
原理:extern int a;
告诉编译器 “此处的 a
是外部全局变量”,从而绕过局部变量的屏蔽,直接访问全局版本。声明需放在局部作用域内(如代码块 {}
中),避免影响其他部分对局部变量的使用。
此外,也可通过 函数封装全局变量 的方式间接访问(适用于复杂场景):
int a = 10; // 全局变量int get_global_a() {return a; // 函数内部无同名局部变量,直接返回全局 a
}int main() {int a = 20; // 局部变量printf("全局变量 a: %d\n", get_global_a()); // 输出 10(通过函数获取全局值)return 0;
}
总结:局部屏蔽全局时,用 extern
显式声明或函数封装可访问全局变量。