前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >⭐️ 关键字深度剖析 ⭐️第七章(关键字volatile\struct\union\enum\typedef)

⭐️ 关键字深度剖析 ⭐️第七章(关键字volatile\struct\union\enum\typedef)

作者头像
用户9645905
发布2022-11-30 08:10:02
3310
发布2022-11-30 08:10:02
举报
文章被收录于专栏:Linux学习~

目录

前言

关键字 - volatile

关于const与volatile

关键字-struct

空结构体多大

struct的内存对齐

柔性数组

struct与class的区别

关键字-union

union和大小端

关键字-enum

enum 与 #define 的区别

关键字-typedef

typedef 与 #define的区别


前言


本章节主要讲解:

  • 深入关键字volatile
  • 深入关键字struct
  • 深入关键字union
  • 深入关键字enum
  • 深入关键字typedef

关键字 - volatile


  • 结论:

volatile是一个类型修饰符,作用是作为指令关键字,一般都是和const对应 用来确保本条指令不会被编译器的优化而忽略(既保持内存可见性)

  • 示例:
  • 不加volatile
代码语言:javascript
复制
int main()
{
	int i = 10;
	int a = i;

	printf("i=%d\n ", i);

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
	__asm
	{
		mov dword ptr[ebp - 4], 20h
	}
	int b = i;
	printf("i=%d\n", b);
	return 0;
}

在debug(调试)版本模式运行程序,输出结果如下: i = 10 i = 32 然后在release版本模式运行下,输出结果如下: i = 10 i = 10

  • 加上volatile
代码语言:javascript
复制
int main()
{
	volatile int i = 10;
	int a = i;

	printf("i=%d\n ", i);

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
	__asm
	{
		mov dword ptr[ebp - 4], 20h
	}
	int b = i;
	printf("i=%d\n", b);
	return 0;
}

分别在debug和release版本运行结果都是如下: i = 10 i = 32

关于const与volatile

const要求你不要进行写入;volatile意思是你读取时,每次都要从内存读,两者并不冲突 所以,一个参数既可以是const还可以是volatile

  • 例如只读的状态寄存器:

它是volatile因为它可能被意想不到地改变 它是const因为程序不应该试图去修改它

关键字-struct


空结构体多大

  • 示例:
代码语言:javascript
复制
struct student
{
}stu;

int main (void)
{
	printf ("sizeof (stu) = %d\n", sizeof (stu));
	return 0;
}
代码语言:javascript
复制
输出结果:
在C中, sizeof (stu) = 0
在C++中, sizeof (stu) = 1

结论:对于空结构体不同编译器理解不同,所以大小不一(可能0或者1)

struct的内存对齐

定义:struct中的各成员变量的存储地址有一套对齐的机制(让CPU能够更舒服地访问变量) struct内存空间的分配是粗放的,不管用不用,全分配

  • 规律:

  1. 每个成员变量的首地址,必须是它的类型的所占字节数的整数倍,如果不满足,它与前一个成员变量之间要填充(padding)一些无意义的字节来满足;
  2. 整个struct的大小,必须是该struct中所有成员的类型中占字节最大者的整数倍,如果不满足,在最后一个成员后面填充
  • 示例:
代码语言:javascript
复制
struct student{
    char sex;
    int score;
};
  • 现象:

第一个char类型成员与第二个int类型成员之间会填充数据,(要求1); 最大长度为整型占用4个字节的空间,所以其占用的空间为4的倍数,这样s占用的空间就是8个字节(要求2)

注意:数据成员的书写顺序会影响结构体占用的空间的大小,尽量将相同数据类型的变量连续书写

柔性数组

  • 定义:

C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员

  • 使用:

sizeof 返回的这种结构大小不包括柔性数组的内存 用malloc()函数进行内存动态分配,分配的内存应该大于结构的大小,以适应柔性数组的预期大小 用malloc函数分配了内存,肯定就需要用free函数来释放内存

  • 示例:
代码语言:javascript
复制
typedef struct data
{
    int len;    //一般用来表示字符数组的字符个数 
    char name[];//空间大小为0

}S; 
int main(void)
{
    S s;
    printf("sizeof(s)=%d\n",sizeof(s));//输出为4,即是int类型大小

    int len = 10; //申请空间 
    struct data *p =(struct data*)malloc(sizeof(s)+sizeof(char)*len);

    //判断是否申请成功&请空处理 

    p->len = len;
    strcpy(p->name,"xxxxxx"); //字符串赋值需要用strcpy

    printf("%s\n",p->name); 

    //释放指针p
    free(p);
    return 0;
}

struct与class的区别

在C++里struct关键字与class关键字一般可以通用 只有一个很小的区别:struct的成员默认情况下属性是public的,而class成员却是private的

关键字-union


  • 定义:

联合(union)是一种节省空间的特殊的类,一个 union 可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值,当某个成员被赋值后其他成员变为未定义状态

  • 使用:

union 主要用来压缩空间:如果一些数据不可能在同一时间同时被用到,则可以使用union

union和大小端

代码语言:javascript
复制
#include<stdio.h>
union var{
        char c[4];
        int i;
};
 
int main(){
        union var data;
        data.c[0] = 0x04;//因为是char类型,值对应ascii
        data.c[1] = 0x03;//16进制便于直接与内存中的值对比
        data.c[2] = 0x02;
        data.c[3] = 0x01;
//数组先使用低地址再使用高地址,内存内容依次为:04,03,02,11(共四字节)
//而把四个字节作为一个整体,对于小端来说:低地址放在低权位
//读取出来则是:0x01020304
//反之则是大端存储模式
        printf("%x\n",data.i);//共用空间
}

关键字-enum


  • 定义:

枚举型是一个集合,其元素(枚举成员)是一些命名的整型常量(元素之间用逗号隔开)

  • 使用:

在程序中,可能需要为某些整数定义一个别名

我们可以利用预处理指令#define来完成这项工作:

代码语言:javascript
复制
#define MON  1
#define TUE  2
#define WED  3
#define THU  4
#define FRI  5
#define SAT  6
#define SUN  7

枚举类型能完成同样的工作(更加简洁便捷):

代码语言:javascript
复制
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

注:第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1 可以人为设定枚举成员的值,从而自定义某个范围内的整数

enum #define 的区别

  1. define是在预处理阶段直接进行替换,并且不进行类型检查,存储在代码段
  2. 枚举则是在程序运行之后才起作用(作用的时期不同),枚举常量存储在数据段的静态存储区里
  3. 枚举变量的大小只能为整型数据(例如:0、1、2…),宏则不是
  4. enum当我们不主动对它进行赋值时,第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1;#define则不会
  5. 枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个
  6. 一般在编译器里,可以调试枚举常量,但是不能调试宏常量
  7. 枚举量具有类型,宏没有类型,枚举变量具有与普通变量相同的性质(如作用域等)而宏没有
  8. 枚举常量属于常量,宏定义不是常量

关键字-typedef


  • 定义:

作用是为一种数据类型(内置数据类型/自定义(struct))定义一个新名字

typedef #define的区别

  1. #define 进行简单的进行字符串替换, #define 宏定义可以使用 #ifdef、#ifndef 等来进行逻辑判断,还可以使用 #undef 来取消定义
  2. typedef 是为一个类型起新名字,typedef 符合(C语言)范围规则,使用 typedef 定义的变量类型,其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置)
  • 示例:
代码语言:javascript
复制
typedef char* pStr1;
#define pStr2 char* 
pStr1 s1, s2;
pStr2 s3, s4;
  •  #define效果:
代码语言:javascript
复制
char* s3, s4;//实际上s4类型是char(与定义前一样)
  • typedef效果:
代码语言:javascript
复制
char *s3, *s4;//类型都是char*
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 关键字 - volatile
    • 关于const与volatile
    • 关键字-struct
      • 空结构体多大
        • struct的内存对齐
          • 柔性数组
            • struct与class的区别
            • 关键字-union
              • union和大小端
              • 关键字-enum
                • enum 与 #define 的区别
                • 关键字-typedef
                  • typedef 与 #define的区别
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档