相关文章链接 : 1.【嵌入式开发】C语言 指针数组 多维数组 2.【嵌入式开发】C语言 命令行参数 函数指针 gdb调试 3.【嵌入式开发】C语言 结构体相关 的 函数 指针 数组 4.【嵌入式开发】gcc 学习笔记(一) - 编译C程序 及 编译过程 5.【C语言】 C 语言 关键字分析 ( 属性关键字 | 常量关键字 | 结构体关键字 | 联合体关键字 | 枚举关键字 | 命名关键字 | 杂项关键字)
每个C语言变量都有自己的属性. 定义变量时可以在变量前加上 “属性关键字” 来为变量定义属性. auto 关键字 : auto 是C语言变量的默认属性, 所有的局部变量都被编译器默认为 auto 属性. 存储在栈中. static 关键字 : 声明静态, 限定作用域. 存储在静态存储区. register关键字 : 声明存储在 CPU 寄存器中. 存储在CPU寄存器中.
auto 关键字 :
>**auto不能修饰全局变量** : auto 关键字不能修饰全局变量, 因为 ***auto 修饰的变量存储在栈内存中, 全局变量存储在全局区, 此时出现了冲突***. 如果使用auto修饰全局变量, 编译时会报错.
存储类型说明 : C 语言中的变量存储 由上到下顺序 : 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区
auto 关键字只能修饰局部变量, 修饰全局变量会报错 :
#include<stdio.h>
//使用auto修饰全局变量,编译时直接报错,因为auto代表存储在栈中, 全局变量存储在全局区, 因此auto只能修饰局部变量, 这里出现错误, 直接注释掉.
auto int global_auto = 0;
正确使用 auto 关键字 :
#include<stdio.h>
//使用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;
}
static 关键字两大作用 :
static 修饰局部变量(声明静态存储区) :
static 修饰全局变量和函数(声明作用域) :
存储类型说明 : C 语言中的变量存储 由上到下顺序 : 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区
static 关键字修饰局部变量, 只初始化一次, 之后每次使用, 都不再进行初始化操作.
static 修饰局部变量示例 : 两个方法中各有一个变量, 一个静态, 一个auto, 分别调用5次方法,进行对比.
#include<stdio.h>
//定义两个函数, 区别是一个是 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 < 5; i ++){
method1();
}
//调用五次定义了static局部变量的值,其中的静态变量只初始化一次,之后每次都用上一次赋值过的变量
for(i = 0; i < 5; i ++){
method2();
}
return 0;
}
分析 : 调用5次method1()方法, 每次local_variable_auto 变量都初始化. 调用5次method2()方法, local_variable_static 变量只初始化一次, 之后每次都沿用上一次的值.
static 关键字 限定变量 只能在本代码中访问被修饰的变量和函数 :
#include<stdio.h>
//引用test_2.c 文件中的普通全局变量,该声明合法.
extern int test_2_global;
//引用test_2.c 中的静态全局变量, 在使用时会报错.
//extern int test_2_global_static;
//引用test_2.c 中的普通函数, 通过该普通函数可以获取test_2.c 中的 test_2_global_static 静态变量
extern int method_3();
//引用test_2.c 中的静态函数, 使用时会报错.
//extern int method_4();
//引用test_2.c 中的普通函数, 通过该普通函数可以调用test_2.c 中的method_4() 静态函数
extern int method_5();
int main()
{
//打印 test_2.c 中的全局变量,查看是否在本文件中引用成功.
printf("%d\n", test_2_global);
//打印 test_2.c 中的静态全局变量, 此时编译时会报错,这里注释掉.
//printf("%d\n", test_2_global_static);
//通过调用 method_3() 获取 test_2.c 中的静态全局变量, 打印出该静态全局变量的值
printf("%d\n", method_3());
//无法调用 test_2.c 中的静态方法, 编译时会报错.
//printf("%d\n", method_4());
//通过调用 method_5, 间接调用 test_2.c 中的 method_4() 静态函数, 获取该静态函数的值并打印出来.
printf("%d\n", method_5());
return 0;
}
//普通的全局变量, 其它文件可以引用该变量
int test_2_global = 666;
//静态全局变量, 同时限定其作用域是本文件, 不能被外部文件使用.
static int test_2_global_static = 444;
//通过调用该方法, 可以在外部文件访问该方法, 获取静态全局变量的值.
int method_3()
{
return test_2_global_static;
}
//使用static修饰该方法, 外部文件无法使用该方法.
static int method_4()
{
return test_2_global_static;
}
//在普通方法中调用static修饰的方法, 此时可以在外部文件中访问该普通方法, 即通过普通方法调用 static 方法.
int method_5()
{
return method_4();
}
register 关键字说明 :
register 使用前提 :
使用情况 : 当需求是***实时性要求效率非常高***时, 就应该使用寄存器变量.
register 不能修饰全局变量 : CPU 寄存器内的变量其生命周期不能太长.
#include<stdio.h>
//使用register 修饰全局变量,此时编译也会报错,全局变量声明周期是整个程序的生命周期,如果将其放入CPU寄存器,
//会导致寄存器占用, 因此编译器规定寄存器变量不能是全局变量. 这里将错误代码注释掉.
register int global_register = 0;
register 变量无法获取地址 :
#include<stdio.h>
int main()
{
//register 关键字只能修饰局部变量,不能修饰全局变量
register int register_variable = 0;
//尝试获取CPU寄存器的地址, 此时编译时会报错. 这里注释掉.
printf("%0x\n", ®ister_variable);
return 0;
}
属性关键字综合示例 :
#include<stdio.h>
//使用auto修饰全局变量,编译时直接报错,因为auto代表存储在栈中, 全局变量存储在全局区, 因此auto只能修饰局部变量, 这里出现错误, 直接注释掉.
//auto int global_auto = 0;
int global_auto = 0;//该声明合法
//使用register 修饰全局变量,此时编译也会报错,全局变量声明周期是整个程序的生命周期,如果将其放入CPU寄存器,
//会导致寄存器占用, 因此编译器规定寄存器变量不能是全局变量. 这里将错误代码注释掉.
//register int global_register = 0;
int global_register = 0;//该声明合法
//定义两个函数, 区别是一个是 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);
}
//引用test_2.c 文件中的普通全局变量,该声明合法.
extern int test_2_global;
//引用test_2.c 中的静态全局变量, 在使用时会报错.
//extern int test_2_global_static;
//引用test_2.c 中的普通函数, 通过该普通函数可以获取test_2.c 中的 test_2_global_static 静态变量
extern int method_3();
//引用test_2.c 中的静态函数, 使用时会报错.
//extern int method_4();
//引用test_2.c 中的普通函数, 通过该普通函数可以调用test_2.c 中的method_4() 静态函数
extern int method_5();
int main()
{
//auto 关键字只能修饰局部变量, 不能修饰全局变量
auto int auto_variable = 0;
//static 既可以修饰局部变量(声明存储于静态存储区), 又可以修饰全局变量(文件作用域限定)
static int static_variable = 0;
//register 关键字只能修饰局部变量,不能修饰全局变量
register int register_variable = 0;
//获取局部变量的地址,该地址是栈内存地址
printf("%0x\n", &auto_variable);
//获取静态变量的地址, 该地址是静态区地址
printf("%0x\n", &static_variable);
//尝试获取CPU寄存器的地址, 此时编译时会报错. 这里注释掉.
//printf("%0x\n", ®ister_variable);
//C编译器中可以不声明, 默认局部变量时 auto 属性的.
auto int i = 0;
//调用五次定义了auto局部变量的值,其中的局部变量每次都初始化
for(i = 0; i < 5; i ++){
method1();
}
//调用五次定义了static局部变量的值,其中的静态变量只初始化一次,之后每次都用上一次赋值过的变量
for(i = 0; i < 5; i ++){
method2();
}
//打印 test_2.c 中的全局变量,查看是否在本文件中引用成功.
printf("%d\n", test_2_global);
//打印 test_2.c 中的静态全局变量, 此时编译时会报错,这里注释掉.
//printf("%d\n", test_2_global_static);
//通过调用 method_3() 获取 test_2.c 中的静态全局变量, 打印出该静态全局变量的值
printf("%d\n", method_3());
//无法调用 test_2.c 中的静态方法, 编译时会报错.
//printf("%d\n", method_4());
//通过调用 method_5, 间接调用 test_2.c 中的 method_4() 静态函数, 获取该静态函数的值并打印出来.
printf("%d\n", method_5());
return 0;
}
//普通的全局变量, 其它文件可以引用该变量
int test_2_global = 666;
//静态全局变量, 同时限定其作用域是本文件, 不能被外部文件使用.
static int test_2_global_static = 444;
//通过调用该方法, 可以在外部文件访问该方法, 获取静态全局变量的值.
int method_3()
{
return test_2_global_static;
}
//使用static修饰该方法, 外部文件无法使用该方法.
static int method_4()
{
return test_2_global_static;
}
//在普通方法中调用static修饰的方法, 此时可以在外部文件中访问该普通方法, 即通过普通方法调用 static 方法.
int method_5()
{
return method_4();
}
goto 现状 (建议禁用) : 一般不使用 goto;
void 关键字作用 : 修饰函数 返回值 和 参数;
void 类型大小C语言规范没有规定, C 语言中是没有 void 变量的. 使用sizeof查看void大小, gcc 返回1 这是编译器厂商给的一个值, 不是C语言中规定的.
void 不能修饰变量, 否则会报错.
void * 指针说明 :
使用 void * 指针实现 memset 方法示例 :
#include<stdio.h>
//实现 memset 函数, 下面是memset函数的内容.
//void *memset(void *s, int ch, size_t n);
//函数解析:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s
//memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
//实现方法 :
//1.接收参数 : void *s 内存地址, int ch 每个字节赋值内容, int size 替换的字节个数.
//2.算法实现 : for 循环实现设置
//3.返回值 : void *
void * memset(void *p, char v, int size)
{
//接收一个任意的内存地址值(任意类型的指针变量)
void * ret = p;
//将 void * 强制转换为 char *
char * dest = (char*)p;
int i = 0;
for(i = 0; i < size; i ++){
//使用 char 类型指针, 依次将之后的字节每个设置成 v
dest[i] = v;
}
return ret;
}
int main()
{
//定义一个数组, 之后我们将使用自定义的memset方法重置数组中的内容
int array[5] = {1, 2, 3, 4, 5};
//循环控制变量
int i = 0;
//打印数组的原始值
for(i = 0; i < 5; i ++){
printf("%d\n", array[i]);
}
//调用自己定义的memset函数清空数组内容
memset(array, 0, sizeof(array));
//打印数组经过memset重置后的数值
for(i = 0; i < 5; i ++){
printf("%d\n", array[i]);
}
//定义long类型测试
long l = 66666;
printf("%ld\n", l); //打印值
memset(&l, 0, sizeof(l)); //重置long变量
printf("%ld\n", l); //再次打印重置后的值
return 0;
}
extern 关键字说明 :
extern "C"
{
...
}
extern 引用外部文件 :
#include <stdio.h>
//引用外部文件 test_2.c 中定义的全局变量
extern int test_2_a;
//引用外部文件 test_2.c 中定义的方法
extern int test_2_get_min(int a, int b);
int main()
{
//调用外部变量 test_2_a, 并打印出其值
printf("%d\n", test_2_a);
//调用外部函数 test_2_get_min , 并打印结果
printf("%d\n", test_2_get_min(666, 888));
return 0;
}
//test_2.c 中定义的全局变量
int test_2_a = 666;
//test_2.c 中定义的函数
int test_2_get_min(int a, int b)
{
//返回a和b中较小的值
return (a < b) ? a : b;
}
extern 指定编译方式代码示例 :
#include <stdio.h>
//如果在 gcc 编译器中, 该用法直接报错
//在 g++ 编译器中, 该用法有效
extern "C"
{
int c_get_min(int a, int b)
{
//返回a和b中较小的值
return (a < b) ? a : b;
}
}
int main()
{
//g++ 编译器中编译通过即可执行
printf("%d\n", c_get_min(666, 888));
return 0;
}
sizeof 关键字说明 :
###(2) sizeof 关键字 代码示例 ( 使用方法 )
sizeof 关键字 代码示例 :
#include <stdio.h>
int main()
{
int a;
//这种sizeof, 将变量放在括号里, 与函数调用类似
printf("%ld\n", sizeof(a));
//可以不写括号, 也可以打印出 变量 a 的大小, 注意 类型 不能这么写
//只有变量可以这么写
printf("%ld\n", sizeof a);
//可以传入类型 int, 打印出 int 类型占用内存大小
printf("%ld\n", sizeof(int));
return 0;
}
const 关键字 说明 :
const 只是针对编译器是有用的, 在运行的时候 就没有这种约束了, 可以改变其值.
编译器处理 const 常量过程 :
常量标示符 | 常量类型 | 常量值 |
---|---|---|
const_variable | int | 666 |
const 修饰数组 :
const 修饰指针 : 需要符合下面的规则 :
声明 | 特征 |
---|---|
const int* p | p指针地址可变 p指针指向的内容不可变 (const 在 * 左边, 数据不可变) |
int const* p | p指针地址可变 p指针指向的内容不可变 (const 在 * 左边, 数据不可变) |
int* const p | p指针地址不可变 p指针指向的内容不可变 (const 在 * 右边, 地址不可变) |
const int* const p | p指针地址不可变 p指针指向的内容不可变 (const 在 * 左边 和 右边, 数据和地址都不可变) |
>**const 修饰指针规则** : ***左数 右指 (左边数据是常量, 右边指针是常量)***; >**左数** : ***const 出现在 * 左边时, 指针指向的数据为常量***, 指向的数据不可改变; >**右指** : ***const 出现在 * 右边时, 指针地址本身是常量***, 指针地址不可改变;
const 修饰函数参数 和 返回值 :
const 关键字 代码示例 : const 常量不能被赋值.
#include <stdio.h>
int main()
{
//定义一个 const 变量, 直接赋值编译器报错, 但是使用指针改变该地址的值是可以的.
const int const_variable = 666;
printf("%d\n", const_variable);
//const 变量不能被直接赋值, 这样在编译的时候就会报错
const_variable = 444;
printf("%d\n", const_variable);
return 0;
}
const 常量一旦作为左值, 编译时就会报错
const 关键字 代码示例 : const 常量可以通过指针修改
#include <stdio.h>
int main()
{
//定义一个 const 变量, 直接赋值编译器报错, 但是使用指针改变该地址的值是可以的.
const int const_variable = 666;
printf("%d\n", const_variable);
//const 变量不能被直接赋值, 这样在编译的时候就会报错, 这里注释掉
//const_variable = 444;
//获取 const 变量的地址, 并改变该地址的值
int* p = (int*) &const_variable;
*p = 888;
printf("%d\n", const_variable);
return 0;
}
通过指针可以修改 const 常量
const 修饰指针规则 : 左数右指; 左数 : const 出现在 * 左边时, 指针指向的数据为常量, 指向的数据不可改变; 右指 : const 出现在 * 右边时, 指针地址本身是常量, 指针地址不可改变;
const 关键字 代码示例 : 修饰指针
#include <stdio.h>
int main()
{
//定义普通的变量, 用于取地址用
int i = 666;
//定义一个 const 在 * 左边的例子, 意义是 指针指向的内容是常量
//按照规则, 指针地址可改变, 指针指向的数据不可变
const int* p = &i;
//指针指向的数据不可改变, 这里会报错
*p = 444;
return 0;
}
#include <stdio.h>
int main()
{
//定义普通的变量, 用于取地址用
int i = 666;
//定义一个 const 在 * 左边的例子, 意义是 指针指向的内容是常量
//按照规则, 指针地址可改变, 指针指向的数据不可变
int const* p = &i;
//指针指向的数据不可改变, 这里会报错
*p = 444;
return 0;
}
#include <stdio.h>
int main()
{
//定义普通的变量, 用于取地址用
int i = 666;
//定义一个 const 在 * 右边的例子, 意思是 地址是常量
//按照规则, 指针地址不可改变, 指针指向的内容可变
int* const p = &i;
//指针指向的数据不可改变, 这里会报错
p = NULL;
return 0;
}
#include <stdio.h>
int main()
{
//定义普通的变量, 用于取地址用
int i = 666;
//定义 const 同时出现在 * 左边 和 右边, 则指针的地址 和 指向的数据都不可改变
const int* const p = &i;
//下面的两个操作, 一个是想修改指针地址, 一个是想修改指针值, 这两个都报错.
p = NULL;
*p = 444;
return 0;
}
const 关键字 代码示例 : const 修饰返回值
#include <stdio.h>
//返回的指针 使用 const 修饰,
//const 在 指针* 的左边, 即其指向的内容是常量, 不可更改
const int* function()
{
//声明静态局部变量,该变量只初始化一次, 之后重复使用
static int count = 0;
count ++;
return &count;
}
int main()
{
//使用 const int* 类型才可以接收 返回值是 const int* 类型的返回值
//如果没有 const 修饰, 会报警告
const int* p = function();
printf("%d\n", *p);
return 0;
}
volatile 关键字简介 :
编译器优化案例 : 有时我们不需要编译器的优化, 有时编译器优化完了反而得不到我们想要的执行效果 ;
#include <stdio.h>
#include <unistd.h>
int main()
{
//value 全程没有做过左值, 值当做右值为 a 和 b 赋值用
//编译器会将 value 当做常量, 使用 666 替代 value
//如果使用 valatile 修饰value, 在编译的时候, 编译器就不会进行这种替换.
int value = 666;
//a 和 b 初始值为0
int a = 0;
int b = 0;
//编译器在编译时, 直接将 666 赋值给了 a
a = value;
sleep(1000);
//如果在休眠的 1000 ms,
//value内存值变成了 888, 我们想要的是888, 但是编译器自作主张将 b 赋值为了 666
//这样就无法实现我们想要的意图
b = value;
return 0;
}
结构体定义 :
//定义结构体
struct Student
{
char* name;
int age;
};
//声明结构体变量
struct Student stu;
//定义结构体的同时 声明结构体变量
struct Student
{
char* name;
int age;
}stu;
//定义结构体的同时 声明结构体变量, 如果不给出结构体类型名称, 在别处不能声明该类型的结构体变量
struct
{
char* name;
int age;
}stu;
//定义结构体类型, 并给 _student 定义一个别名 student
typedef struct _student
{
char* name;
int age;
}student;
//声明结构体变量
student stu;
-5.定义结构体别名 但是没有给出结构体的类型名称 : 如果使用 typedef 定义了一个结构体的别名, 那么该结构体可以不定义结构体类型名称;
//定义结构体类型, 并定义一个别名 student, 可以不定义结构体的类型名称
typedef struct
{
char* name;
int age;
}student;
//声明结构体变量
student stu;
空结构体占用内存大小 :
#include <stdio.h>
//定义一个空结构体,用来测试空结构体的大小
struct A
{
};
int main()
{
//定义两个空结构体变量,打印其大小和地址值
struct A a1;
struct A a2;
//打印空结构体类型大小
printf("%ld\n", sizeof(struct A));
//打印两个空结构体大小 和 空结构体变量地址
printf("%ld, %0X\n", sizeof(a1), &a1);
printf("%ld, %0X\n", sizeof(a2), &a2);
return 0;
}
空结构体变量类型大小为0,其变量的大小为0,其地址错位1.
柔性数组 :
#include <stdio.h>
#include<stdlib.h>
//定义柔性数组
typedef struct soft_array
{
int len;
int array[];
} soft_array;
int main()
{
//打印 结构体 soft_array 的类型大小, 结果是4字节
//分析 : int array[] 是一个未知大小的数组, 编译器不知道该数组多大, 就将该数组大小当做0
//sizeof 计算的 结构体的 4 个字节是 int 类型的大小, 后面的 int array[] 只是占位符, 可以分配任意大小的数组
printf("%ld\n", sizeof(soft_array));
//为柔性数组分配内存空间, 结构体的基本空间 + 数组大小
soft_array* array = (soft_array*)malloc(sizeof(soft_array) + sizeof(int) * 10);
//设置柔性数组大小
array->len = 10;
int i = 0;
//以此遍历为柔性数组赋值
for(i = 0; i < array->len; i ++)
{
array->array[i] = i;
}
//依次遍历打印柔性数组的值
for(i = 0; i < array->len; i ++)
{
printf("%d\n", array->array[i]);
}
return 0;
}
柔性数组使用 :
#include <stdio.h>
#include<stdlib.h>
/*
柔性数组实现斐波那契数列
1. 定义柔性数组结构, typedef struct soft_array 实现;
2. 创建柔性数组, 编写一个创建函数 create_array() 方法;
3. 生成斐波那契数列, generate_array() 方法;
4. 释放柔性数组, delete_array() 方法.
*/
//1.定义柔性数组结构体
typedef struct soft_array
{
int len;
int array[];
} soft_array;
//2.创建柔性数组的函数
soft_array* create_array(int array_size)
{
soft_array* array = NULL;
//数组大小必须大于0
if(array_size > 0)
{
//从堆空间申请一个柔性数组内存空间
array = (soft_array*)malloc(sizeof(*array) + sizeof(*(array->array)) * array_size);
array->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 < array->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 < array->len; i ++)
{
printf("%d\n", array->array[i]);
}
//释放柔性数组
delete_array(array);
return 0;
}
struct 和 union 的区别 :
#include <stdio.h>
//结构体需要为所有的元素分配内存空间
//该结构体占 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;
}
union 联合体 受大小端 影响 :
通过 union 判断系统的大小端 :
#include <stdio.h>
//利用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;
}
enum 简介 :
enum 枚举代码示例 :
#include <stdio.h>
//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;
}
enum 与 define 区别 :
#include <stdio.h>
#define LEN 888
int main()
{
//在编译的时候, #define 定义的 LEN 直接替换成 888 数字
int i = LEN;
int array[LEN];
return 0;
}
typedef 介绍 :
typedef 与 define 区别 :
#include <stdio.h>
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;
}