前言
- 学习资源:b站up主:底层技术栈
- 学过C语言都知道,全局变量可以再全局中使用,其实全局变量内部还是涉及到不少知识,这里从
内存分区、汇编视角看类型、连接器
等角度看待全局变量; 由于涉及到底层技术,如果有错误,请各位大佬指点
🌩 以以下代码为例
#include <stdio.h>
// 定义全局变量
int a = 123;
int* p = &a;
int main()
{
printf("a: %d, p: %x\n", a, p);
return 0;
}
📅 全局数据
在C语言中属于全局数据的有三个:
- 函数都是全局的
- 字符串常量
- 全局的变量
注意: 全局数据不等于全局变量!!!
案例中:
- 变量a、p都属于全局变量
📝 C语言内存分区
我们之前学过内存四区:栈区、堆区、全局区、代码区(从高地址向低地址),在C语言中,如果细分,可以将全局区分为:常量区与全局(静态)区,如图所示。
注意:堆区内存不连续,地址向下增长,栈区内存连续,地址向下增长。
案例中:
- 变量a、p都存储在全局区(.data)区,拥有读写权限
🤗 汇编视角看类型
在汇编语言中,只有指令,没有类型这一概念,类型是高级语言抽象出来的,目的是为了调用不同的指令,特殊的指令被高级语言抽象出来了汇编,如:
int a >> 4,这里是有符号,故属于算术右移,有符号,高位填符号位,** 汇编 调用asr指令**
unsigned int a >> 4,这里是无符号,故属于逻辑右移,高位填0,** 汇编 调用shr指令**
🔗 连接器
连接器作用: 连接代码所需要的API的二进制代码,比如printf。从内存来看,连接器对整个(最终的可执行文件)程序的“内存布局”规划好后,全局变量都是常量, 并且在main函数调用前就被初始化好了,本人认为这也是为什么全局变量自动初始化为0的原因了。
🤔 联系栈区
栈区存储局部变量,局部变量在没有初始化前,他的值是任意的,那是因为对于栈区的变量来说,都是程序执行到那个阶段才会给那个变量分配内存,联想函数,这也就是意味着在函数中局部变量的内存只有在调用函数的时候才会给他的变量分配内存,这样就解释了为什么输出一个未初始化的局部变量是乱码,而且每一次都不一样的原因了,函数存储在代码区,这也是程序分区,实现了程序更好的管理。
❔ 例子
// 全局变量
struct temp {
void (*add)(int, int); // 8字节
void (*dev)(int, int); // 8字节
};
这是一个结构体,里卖定义了两个函数指针,这个结构体和这两个指针,在连接器对程序的整个“内存布局”都规划好后,都是常量了,并且如果没有在全局变量中赋值,则默认都赋值为0。