
🐇
🔥博客主页: 云曦 
📋系列专栏:深入理解C语言💨吾生也有涯,而知也无涯 💛 感谢大家👍点赞 😋关注📝评论 
文章目录
- 前言
 - 一、关键字 - static
 - 📙1.1 修饰变量
 - 📝1.1.1 修饰局部变量
 - 📝1.1.2 修饰全局变量
 
- 📙1.2 修饰函数
 - 📙1.3static总结
 
- 二、关键字 - sizeof
 - 📙2.1 基本数据类型
 - 2.2 📙数据类型与"模子"
 - 📝2.2.1 C常见的内置类型
 - 📝2.2.2 如何看待数据类型
 
- 2.3 📙变量的命名规则
 - 📝规则1
 - 📝规则2
 - 📝规则3
 - 📝规则4
 - 📝规则5
 - 📝规则6
 - 📝规则7
 - 📝规则8
 - 📝规则9
 - 📝规则10
 
- 📙2.4 sizeof的理解
 - 📙2.5 sizeof的总结
 
- 三、signed、unsigned关键字
 - 📙3.1 原反补
 - 📙3.2 二进制十进制快速转换口诀
 - 📙3.3 变量的存入和取出
 - 📙3.4 大小端
 - 📙3.5 深入理解变量的存入和取出
 - 📙3.6 为什么存储的都是补码
 - 📙3.7 数据类型的取值范围
 
前言
在上期我们学习了两个关键字,本期将继续深入理解另外的关键字。
一、关键字 - static
📙1.1 修饰变量
📝1.1.1 修饰局部变量
//i是局部变量,具有局域临时性
//函数调用开辟空间并初始化
//函数结束释放空间
void fun()
{
	//static修饰后改变了i的生命周期
	//但没有改变i的作用域
	static int i = 0;
	i++;
	printf("%d\n", i);
}
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		fun();
	}
	return 0;
}
 
static修饰局部变量,更改局部变量的生命周期(临时变量->全局生命周期,但作用域不变)
📝1.1.2 修饰全局变量
- test.c
 
#include"test.h"
static int g_val = 100;
void fun()
{
	printf("hello world!\n");
}
 
- test.h
 
#include<stdio.h>
extern g_val;
extern void fun();
 
- main.c
 
#include"test.h"
int main()
{
	printf("%d\n", g_val);
	fun();
	return 0;
}
 
static修饰全局变量,该变量只在本文件内被访问,不能被外部其他文件直接访问。
📙1.2 修饰函数
- test.c
 
#include"test.h"
static void fun()
{
	printf("hello world!\n");
}
 
- test.h
 
#pragma once
#include<stdio.h>
extern void fun();
 
- main.c
 
#include"test.h"
int main()
{
	fun();
	return 0;
}
 
static修饰函数,该函数只能在本文件内被访问,不能被外部其他文件直接
虽然static修饰的函数不能被直接访问,但可以通过间接来访问:
- tast.c
 
#include"test.h"
static void fun()
{
	printf("hello world!\n");
}
void F()
{
	fun();
}
 
- test.h
 
#pragma once
#include<stdio.h>
extern void F();
 
- main.c
 
#include"test.h"
int main()
{
	F();
	return 0;
}
 
📙1.3static总结
- 在static修饰函数时:提高了项目的维护、提供安全保证。
 - 总的来说:static是C语言为用户提供安全保证的一个关键字。
 
二、关键字 - sizeof
📙2.1 基本数据类型

2.2 📙数据类型与"模子"
📝2.2.1 C常见的内置类型
| C常见内置类型 | 
|---|
| int | 
| short | 
| long | 
| long long | 
| char | 
| float | 
| double | 
📝2.2.2 如何看待数据类型
- 定义变量的本质是:在内存中开辟一块空间,用于保存数据。
 - 定义变量是需要类型的,而类型决定了:开辟空间的大小。
 
int main()
{
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof(short));//2
	printf("%d\n", sizeof(long));//4
	printf("%d\n", sizeof(long long));//8
	printf("%d\n", sizeof(char));//1
	printf("%d\n", sizeof(float));//4
	printf("%d\n", sizeof(double));//8
	return 0;
}
 

- C中为何有数据类型:本质是对内存进行合理划分,按需索取。
 - 类型为什么在C中有这么多:应用的场景不同,解决应用场景对应得计算方式不同,需要空间的大小是不同的。
 
本质就是:用最小成本,解决各种多样化的场景问题。
其实数据类型就相当于做月饼的模具:做什么样的月饼,用什么样的模具
2.3 📙变量的命名规则
📝规则1
标识符最好采用英文单词或其组合,不允许使用拼音。程序中的英文单词一般不要太复杂,用词应当准确。
- 例如:
 
int main()
{
	fun();//全称为function
	return 0;
}
 
📝规则2
标识符的长度应当符合“min-length && max-information”原则。
- 例如:
 
int main()
{
	int MaxValueUntilOverflow = 0;
	int MaxVal = 0;
	
	return 0;
}
 
名字不要过长,过长的单词简写就行。
📝规则3
- 当标识符由多个单词组成时,每个单词的首字符要大写,这样可以区分每个单词。
 - 这种命名的方式叫作:大小驼峰。
 
- 举例:
 
int main()
{
	int MaxVal = 0;
	
	return 0;
}
 
📝规则4
尽量避免名字中出现数字编号,如:
int main()
{
	int Value1 = 0;
	int Value2 = 0;
	return 0;
}
 
但只是尽量,在特定的场景下是可以这样写的。
📝规则5
对在多个文件之间共同使用的全局变量要加范围限定符,如:
int g_val = 100;//全称为global variable
 
全局变量可以在变量名前面加上g_表示全局变量。
📝规则6
程序中不得出现仅靠大小写区分的相似的标识符,如:
int main()
{
	int x = 0;
	int X = 0;
	foo();
	FOO();
	return 0;
}
 
这样的命名会导致代码的可读性变差,例如:l和数字1、I和(L的小写l)。
📝规则7
一个函数名禁止被用于其它之处。例如:
int fun(int x)
{
	return x * x;
}
int main()
{
	int fun = 10;
	return 0;
}
 
函数名为fun,但在mian函数里有个fun的局部变量,这样的命名是禁止的,容易让人误解且代码可读性低。
📝规则8
所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。例如:
#define MAX_INT 10
 
📝规则9
局部变量中可以采用通用的命名方式,但仅限于
i、j、n、k等作为循环变量使用。
使用时不可以出现以下几个形式:
int main()
{
	//定义变量时不能出现这样的定义
	int   x;
	char    ch;
	int * p;
	return 0;
}
 
定义局部变量一般来说:
- 用
 i、j、k、n、m等表示int类型。- 用
 c、ch等表示字符型。- 用
 a、arr等表示数组。- 用
 p等表示指针。- 除了
 i、j、k可以表示循环的变量名以外,别的变量名尽量不要使用。
📝规则10
- 定义变量的同时要记得初始化。定义变量时,变量的值不一定清空。
 - 像局部变量,不做初始化,它的内容就是随机值。
 - VS2022上不做初始化,内容就是随机值且VS2022会报警告
 
- 在Linux系统上定义的变量不初始化,它的内容是0.
 - 定义的变量,不初始化,它的内容是什么具体看编译器,但还是希望大家定义变量时,给变量初始化一下。
 
📙2.4 sizeof的理解
- 有人会认为sizeof是一个函数,但其实sizeof不是函数,它只是一个关键字(操作符)而已。
 - sizeof是用来计算一个类型的大小的。
 - sizeof要注意的是以下问题:
 
#include<stdio.h>
int main()
{
    int a = 0;
    //sizeof a是可以这样写的
    printf("%d\n", sizeof a);
    //sizeof int是不能这样写的
    printf("%d\n", sizeof int);
   
    return 0;
}
 
直接计算类型要带(),计算变量可以不带括号。
📙2.5 sizeof的总结
sizeof是用来计算在空间占用的字节大小的一个操作符,且sizeof是一个操作符。
三、signed、unsigned关键字
📙3.1 原反补
- 相信大家已经学过原反补的概念了,我这里就简单叙述一遍:
 - 整型的原反补是相同的
 - 负数的原反补不相同,要通过计算得来,而负数的原反补计算过程为:
 
- 原码变反码 - 符号位不变其他位按位取反。
 - 反码变补码 - 反码加1
 
- 负数从补码变为原码的计算过程有两种方法:
 
- 方法1
 
- 倒着回去
 
- 补码变反码 - 补码-1
 - 反码变原码 - 符号位不变其他位按位取反
 
- 方法2
 
- 按原码变补码的操作在进行一次:
 
- 补码变反码 - 符号位不变其他位按位取反
 - 反码变原码 - 反码加1
 
int main()
{
    //整型的原反补是相同的
    int a = 10;
    //0000 0000 0000 0000 0000 0000 0000 1010 - 原码
    //0000 0000 0000 0000 0000 0000 0000 1010 - 反码
    //0000 0000 0000 0000 0000 0000 0000 1010 - 补码
    int b = -10;
    //1000 0000 0000 0000 0000 0000 0000 1010 - 原码
    //1111 1111 1111 1111 1111 1111 1111 0101 - 反码
    //1111 1111 1111 1111 1111 1111 1111 0110 - 补码
    
    return 0;
}
 
两种方法都可以,但要记住用的时候可以用方法1推,但实际上理解的时候要用方法2来理解,因为计算机使用的是方法2来进行计算的
📙3.2 二进制十进制快速转换口诀
想必大家在进行二进制转十进制或十进制转二进制的时候,计算的速度会很慢,所以给大家推荐一套二进制十进制相互快速转换的口诀
📙3.3 变量的存入和取出
int main()
{
    unsigned int a = -10;
    printf("%d\n", a);
    printf("%u\n", a);
    
    return 0;
}
 
上面代码的打印结果是什么呢?
答案是:10和4294967286,%d打印的是有符号数,而%u打印的是无符号数,无符号数的意思就是不把第一个比特位看成符号位了。
- 结论:
 
- 变量存和取的过程:
 - 存:字面数据要先转换为补码,在放入空间中,所以符号位,完全是看数据本身的正负号,与有无符号无关。
 - 取:取数据一定要先看数据本身类型,然后才决定要不要最高位的符号位,如果不需要直接二进制转十进制,如果需要,则先转成原码然后才能识别。(当然,最高符号位在那么,又要明确大小端)
 
📙3.4 大小端
VS2022的内存布局
大小端:
大小端基本概念:
- 大端:按字节为单位,低权值位数据存储在高地址处,就叫大端
 - 小端:按字节为单位,低权值位数据存储在低地址处,就叫小端
 
- 大小端快速知晓口诀:
 
- 小端口诀:小小小
 - 大端口诀:除小小小以外的都认为是大端
 - 小小小的含义:第一个小:权值位比较小,第二个小:地址数字比较小,第三个小:小端的小。
 
📙3.5 深入理解变量的存入和取出
- 存:看大小端存储
 - 取:先看大小端,再看自身类型
 
📙3.6 为什么存储的都是补码
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理; 同时,加法和减法也可以统一处理(CPU只有加法器)。此外,补码与原码相互转换,其运算过程是相的,不需要额外的硬件电路。
📙3.7 数据类型的取值范围
这里以signed char为例:
所谓特定数据类型,能表示多少个数据,取决于多少个比特位对应的排列组合的个数。
- 数据类型对应的取值大小
 
| 整型 | 存储大小 | 数值范围 | unsigned(无符号)数值范围 | 
|---|---|---|---|
| char | 1字节(byte) | [-128 ~ 127] | [0 ~ 255] | 
| int | 4字节(byte) | [-2147483648 ~ 2147483647] | [0 ~ 4294967295] | 
| short | 2字节(byte) | [-32768 ~ 32767] | [0 ~ 65535] | 
| long | 4字节(byte) | [-2147483648 ~ 2147483647] | 0 ~ 4294967295 | 
| long long | 8字节(byte) | ±9.2233720368548E+4932 | [0 ~ 1844674407371E+19] | 
| 浮点型 | 存储大小 | 数值范围 | 精度 | 
|---|---|---|---|
| float | 4字节(byte) | [1.2E-38 ~ 3.4E+38] | 6位有效位 | 
| double | 8字节(byte) | [2.3E-308 ~ 1.7E+308] | 15位有效位 | 
| long double | 16字节(byte) | [3.4E-4932 ~ 1.1E+4932] | 19位有效位 | 































