相关文章链接 : 1.【嵌入式开发】C语言 指针数组 多维数组 2.【嵌入式开发】C语言 命令行参数 函数指针 gdb调试 3.【嵌入式开发】C语言 结构体相关 的 函数 指针 数组 4.【嵌入式开发】gcc 学习笔记(一) - 编译C程序 及 编译过程 5.【C语言】 C 语言 关键字分析 ( 属性关键字 | 常量关键字 | 结构体关键字 | 联合体关键字 | 枚举关键字 | 命名关键字 | 杂项关键字)
- 一. 属性关键字 (auto | static | register)
- 1. auto 关键字
- (1) auto 关键字说明 ( 默认属性 | 声明栈存储 | 只能修饰局部变量 [ 全局变量在全局区存储 , auto 在栈内存中 ] )
- (2) auto 关键字 代码示例 ( 不能修饰全局变量 | 错误示例 )
- (3) auto 关键代码示例 ( 正确用法 )
- 2. static 关键字
- (1) static 关键字说明 ( ① 声明静态属性 存储于静态区 [ 修饰局部变量 ] | ② 文件作用域限定符 [ 修饰全局变量 和 函数 ] )
- (2) static 关键字 代码示例 ( 修饰局部变量 )
- (3) static 关键字 代码示例 ( 限定变量和方法 作用域 )
- 3. register 关键字
- (1) register关键字说明 ( 声明寄存器存储 ( 不确定 ) | 适用前提 ① 值符合CPU要求 ② 不能用 & 取地址 , & 只能取内存地址 不能取 CPU 地址 )
- (2) register 关键字代码示例 ( 不能修饰全局变量 | 错误示例 )
- (3) register 关键字代码示例 ( 不能获取register变量地址 | 错误示例 )
- 4. 属性关键字综合示例
- 二. 其它关键字 ( goto | void | extern | sizeof)
- 1. goto 关键字 ( 不建议使用 )
- 2. void 关键字
- (1) void 关键字说明 ( 修饰 返回值 和 参数 | 本质 代表 没有 )
- (2) void * 指针介绍 ( 被赋值 [ 左值 ] 时可以被赋值为任意指针类型变量 | 右值 赋值给其它类型变量时 需要将 void* 指针强转为被赋值的类型 )
- (3) void * 指针 代码示例 ( 实现 memset 方法 )
- 3. extern 关键字
- (1) extern 关键字说明 ( 声明外部文件的 变量 和 函数 | 设置编译方式 C++ 中 命令编译器 以 标准 C 规范编译 变量 和 函数 )
- (2) extern 引用外部文件示例 ( 声明外部变量 : extern 类型 变量名称; | 声明外部函数 : extern 返回值类型 函数名称 ( 参数列表 ) ; )
- (3) extern 关键字代码示例 ( 编译方式 )
- 4. sizeof 关键字
- (1) sizeof 关键字说明 ( 本质 不是函数 是 编译器 指示符 | 编译过程中得到结果 | 计算变量 或 类型 占用内存大小 )
- 三. 常量 和 易变 关键字 ( const | volatile )
- 1. const 关键字 简介
- (1) const 关键字 简介 ( 左数右指 | 修饰制度变量 | 生成常量符号表 )
- (2) const 关键字 代码示例 ( const 常量不能被赋值 | 错误示例)
- (3) const 关键字 代码示例 ( 通过指针修改const常量 : 获取 const 变量的地址, 并改变该地址的值 )
- (4) const 关键字 代码示例 ( 修饰指针 | 错误示例 )
- ( 5 ) const 关键字 代码示例 ( 修饰返回值 )
- 2. volatile 关键字 简介
- (1) volatile 关键字 简介 ( 告诉编译器 每次去内存中取变量值 | )
- (2) volatile 关键字 代码示例
- 四. 结构体 联合体 关键字 ( struct | union )
- 1. struct 关键字
- (1) 结构体定义 使用 ( ① 结构体定义 : struct 结构体名称 {}; | ② 结构体变量声明 : struct 结构体名 变量名 ; | ③ 定义结构体同时声明结构体变量 : struct 结构体名称 {} 变量名 ; | ④ 结构体定义别名 : typedef struct 结构体名称 {} 别名名称; 声明变量 : 别名名称 变量名称 ; [ 定义一个别名后, ] | ⑤ 结构体定义别名省略结构体名称 : typedef struct {} 别名名称; 声明变量 : 别名名称 变量名称 ; )
- (2) struct 结构体大小
- (3) struct 结构体实现柔性数组
- (4) 柔性数组 代码示例 ( 处理斐波那契数列 )
- 3. union 联合体 关键字
- (1) struct 和 union 的区别 ( struct 为每个元素分配独立空间 | union 只为最大的元素分配内存空间 所有元素共享该空间 )
- (2) union 联合体注意事项 ( 受大小端影响 )
- 五. 枚举 关键字 ( enum )
- 1. enum 关键字
- (1) enum 枚举关键介绍 ( 定义常量 | 只能定义 int 类型 )
- (2) enum 枚举代码示例
- (3) enum 和 define 区别 ( #define 编译时进行替换 | enum 是常量值 )
- 2. typedef 关键字
- ( 1 ) typedef 关键字介绍 ( 给已有类型重新命名 | 没有新类型 | 无法扩展 )
每个C语言变量都有自己的属性. 定义变量时可以在变量前加上 “属性关键字” 来为变量定义属性. auto 关键字 : auto 是C语言变量的默认属性, 所有的局部变量都被编译器默认为 auto 属性. 存储在栈中. static 关键字 : 声明静态, 限定作用域. 存储在静态存储区. register关键字 : 声明存储在 CPU 寄存器中. 存储在CPU寄存器中.
1. auto 关键字 (1) auto 关键字说明 ( 默认属性 | 声明栈存储 | 只能修饰局部变量 [ 全局变量在全局区存储 , auto 在栈内存中 ] )auto 关键字 :
- 1.C语言默认属性 : 如果一个变量前没有写明属性, 那就是默认为 auto 的属性;
- 2.声明栈存储 : 使用auto修饰的变量, 会默认存储在程序的栈中.
- 3.只能修饰局部变量 : auto 关键字只能修饰局部变量, 修饰全局变量编译时会报错.
存储类型说明 : C 语言中的变量存储 由上到下顺序 : 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区
(2) auto 关键字 代码示例 ( 不能修饰全局变量 | 错误示例 )auto 关键字只能修饰局部变量, 修饰全局变量会报错 :
- 1.代码 : test_1.c .
#include
//使用auto修饰全局变量,编译时直接报错,因为auto代表存储在栈中, 全局变量存储在全局区, 因此auto只能修饰局部变量, 这里出现错误, 直接注释掉.
auto int global_auto = 0;
- 2.编译结果 : 提示全局变量不能使用 auto 关键字声明.
正确使用 auto 关键字 :
- 1.代码 :
#include
//使用auto修饰全局变量,编译时直接报错,因为auto代表存储在栈中, 全局变量存储在全局区, 因此auto只能修饰局部变量, 这里出现错误, 直接注释掉.
//auto int global_auto = 0;
int global_auto = 0;//该声明合法
int main()
{
//auto 关键字只能修饰局部变量, 不能修饰全局变量
auto int auto_variable = 0;
//获取局部变量的地址,该地址是栈内存地址
printf("%0X\n", &auto_variable);
return 0;
}
- 2.执行结果 : 打印出了栈内存中的地址.
static 关键字两大作用 :
- 1.静态属性 : static 修饰局部变量 指明变量是静态的, 该变量存储在程序静态区.
- 2.作用域限定符 : static 作为 文件作用域限定符.
static 修饰局部变量(声明静态存储区) :
- 1.作用 : 说明该局部变量存储在静态存储区.
- 2.初始化次数 : 该值只会***初始化一次***, 之后会被不断赋值, 调用该局部变量所在方法, 每次的值都是上次调用该方法计算完毕后的值. 如果是第一次调用, 那么就初始化这唯一的一次.
- 3.声明周期 : 该局部变量的生命周期***从第一次初始化直到程序退出为止***.
static 修饰全局变量和函数(声明作用域) :
- 1.修饰全局变量 : static 如果修饰全局变量, 那么就说明该全局变量只能在本文件中使用, 其它文件无法访问.
- 2.修饰函数 : static 如果修饰函数, 那么该函数只能
存储类型说明 : C 语言中的变量存储 由上到下顺序 : 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区
(2) static 关键字 代码示例 ( 修饰局部变量 )static 关键字修饰局部变量, 只初始化一次, 之后每次使用, 都不再进行初始化操作.
static 修饰局部变量示例 : 两个方法中各有一个变量, 一个静态, 一个auto, 分别调用5次方法,进行对比.
- 1.代码 :
#include
//定义两个函数, 区别是一个是 auto 变量, 一个是 static 变量, 本函数定义是 auto 变量
void method1()
{
//每次调用都调用该值
int local_variable_auto = 0;
local_variable_auto ++;
printf("%d\n", local_variable_auto);
}
//定义两个函数, 区别是一个是 auto 变量, 一个是 static 变量, 本函数定义是 static 变量
void method2()
{
//与method1对比就是局部变量使用 static 修饰
//该变量只初始化一次, 之后调用, 获取的值都是上次用完后的值, 即使被赋值很多次, 获取到的值是最后一次赋值的值.
static int local_variable_static = 0;
local_variable_static ++;
printf("%d\n", local_variable_static);
}
int main()
{
//C编译器中可以不声明, 默认局部变量时 auto 属性的.
auto int i = 0;
//调用五次定义了auto局部变量的值,其中的局部变量每次都初始化
for(i = 0; i len = array_size;
}
return array;
}
//3.生成斐波那契数列并放入柔性数组
void generate_array(soft_array* array)
{
//传入的弹性数组不能为空
if(array != NULL)
{
//第一二项为1,后面第三项开始就是前两项之和
if(array->len == 1)
{
//数组大小就1个直接赋值1
array->array[0] = 1;
}
else if (array->len == 2)
{
//数组大小2个,这两个都赋值1
array->array[0] = 1;
array->array[1] = 1;
}
else
{
//如果超过2个,前两个赋值1,然后依次计算
array->array[0] = 1;
array->array[1] = 1;
int i = 0;
for(i = 2; i len; i ++)
{
array->array[i] = array->array[i - 1] + array->array[i - 2];
}
}
}
}
//4.删除柔性数组
void delete_array(soft_array* array)
{
//释放内存空间
free(array);
}
int main()
{
//创建柔性数组, 为柔性数组分配内存空间, 结构体的基本空间 + 数组大小
soft_array* array = create_array(10);
//生成斐波那契数列
generate_array(array);
int i = 0;
//依次遍历打印柔性数组的值
for(i = 0; i len; i ++)
{
printf("%d\n", array->array[i]);
}
//释放柔性数组
delete_array(array);
return 0;
}
- 2.执行结果 :
struct 和 union 的区别 :
- 1.struct 分配空间 : struct 结构体 为每个结构体元素分配独立的内存空间 ;
- 2.union 分配空间 : union 联合体 只为最大的联合体元素分配内存控件, 所有的元素共享该空间 ;
- 3.struct union 空间分配示例 :
#include
//结构体需要为所有的元素分配内存空间
//该结构体占 8 个字节内存空间
struct A
{
int a;
int b;
};
//联合体只分配最大元素所占的内存空间
//该 联合体 占 4 字节 内存空间
union B
{
int a;
int b;
};
int main()
{
printf("%ld\n", sizeof(struct A));
printf("%ld\n", sizeof(union B));
return 0;
}
- 4.执行结果 :
union 联合体 受大小端 影响 :
- 1.大端模式 : 低位数据放在 高位地址 中;
- 2.小端模式 : 低位数据放在 低位地址 中;
通过 union 判断系统的大小端 :
- 1.代码示例 :
#include
//利用union联合体赋值受大小端影响的特性,
//判断当前的系统是大端模式还是小端模式
int big_or_small_check()
{
//定义联合体,其中定义int和char类型元素,两个元素共用一个内存空间
union check_end
{
int i;
char c;
} a;
//将大空间的int赋值为1
a.i = 1;
//四个字节赋值为1,如果是小端模式,那么高位地址都是0,最低位个字节是1
//char是占用最低位字节, 如果char 为1,说明就是小端模式
if(a.c == 1)
{
printf("small end\n");
}
else
{
printf("big end\n");
}
}
int main()
{
big_or_small_check();
return 0;
}
- 2.执行结果 :
enum 简介 :
- 1.作用 : enum 是自定义类型, 作用是用来定义常量的 ;
- 2.定义要求 : enum 只能定义成 int 类型. 不能定义成 浮点型 ;
enum 枚举代码示例 :
- 1.代码示例 :
#include
//enum 如果没有指明, 默认值是从 0 开始
//如果没有指定值, 那么后面一个默认是在前一个基础上加1
//如果显示的赋值后, 后面的类型依次加 1, 显示赋值之前的默认从 0 开始
//枚举是常量, 不能获取枚举的地址
enum color
{
RED,
YELLOW,
BLUE = 666,
GRAY
};
int main()
{
printf("%d\n", RED);
printf("%d\n", YELLOW);
printf("%d\n", BLUE);
printf("%d\n", GRAY);
return 0;
}
- 2.执行结果 :
enum 与 define 区别 :
- 1.本质 : #define 是在编译的时候进行简单的替换, enum 枚举是常量值.
- 2.能否被调试 : #define 宏 无法调试, enum 可以;
- 3.类型 : #define 没有类型信息, enum 是 有特定的类型 的;
- 代码示例 :
#include
#define LEN 888
int main()
{
//在编译的时候, #define 定义的 LEN 直接替换成 888 数字
int i = LEN;
int array[LEN];
return 0;
}
2. typedef 关键字
( 1 ) typedef 关键字介绍 ( 给已有类型重新命名 | 没有新类型 | 无法扩展 )
typedef 介绍 :
- 1.作用 : typedef 用于给 存在的数据类型 重新命名;
- 2.没有新类型 : typedef 关键字使用, 全程都没有产生 新的数据类型 ;
- 3.类型无法扩展 : 不能使用 unsigned 和 signed 等扩展 typedef 重命名的类型;
typedef 与 define 区别 :
- 1.typedef 本质 : typedef 是给已有类别重新命名;
- 2.define 本质 : define是简单的字符串替换, 没有类别 类型 等其它含义 ;
- 3.代码示例 :
#include
typedef char* PCHAR
#define PINT int*
int main()
{
//这里 p1 和 p2 都是 char* 类型
PCHAR p1, p2;
//这里注意, 编译时PINT 会被替换成 int* p3, p4
//注意 *p3 是指针, p4 是 int 类型数据, int *p3, p4
PINT p3, p4;
return 0;
}