C语言编程C++自定义个性化类型

目录
  • 自定义类型
    • 结构体
      • 声明一个结构体类型
      • 特殊声明
      • 结构体自引用
      • 结构体变量的定义和初始化
      • 结构体内存对齐
      • 结构体传参
      • 位段
    • 枚举
    • 联合(共用体)
      • 联合类型的定义
      • 联合类型的声明
      • 联合的特点
      • 判断当前机器的大小端存储【】

自定义类型

结构体

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量

声明一个结构体类型

//声明一个学生类型,是想通过学生类型来创建学生变量(对象)
//描述学生就得有属性啥的。名字,电话,性别,年龄
struct Stu
{
    char name[20];//名字
    char tele[12];//电话
    char sex[10];//性别
    int age;//年龄
};

struct Stu s3;//创建全局结构体变量

int main()
{
    struct Stu s1;
    struct Stu s2;//创建结构体变量
	return 0;
}

特殊声明

在声明结构的时候,可以不完全的声明。

没有结构体标签

匿名结构体类型

要清楚一点匿名结构体是个类型不占用空间的,就好像int一样,他们没有创建一个变量是不会开辟空间的,所以类型不占用空间就没有销毁不销毁这一说,只有有了空间才会有销毁不销毁这一说,类型就好像图纸,变量才是真正要盖的房子

struct
{
    char name[20];//名字
    char tele[12];//电话
    char sex[10];//性别
    int age;//年龄
}stu;//直接接结构体变量,匿名的时候后面就把变量给创建好,不然之后也用不到这个结构名,因为没有结构体名字怎么创建变量呢

匿名结构体指针类型

struct
{
    char name[20];//名字
    char tele[12];//电话
    char sex[10];//性别
    int age;//年龄
}* pstu;//这时pstu就变成匿名结构体指针了

结构体自引用

在结构中包含一个类型为该结构本身的成员是否可以呢?

所以节点(Node)就出来了

一块表示数据一块表示地址

struct Node
{
	int data;          //数据域
	struct Node* next; //指针域
};

这就是结构体自引用 自己类型里的变量找到同类型的另外一个对象

注意

所以对于结构体的自引用是不能省略自己的结构体标签,下面就是解决方案

typedef struct Node
{
	int data;          //数据域
	struct Node* next; //指针域
}Node;

结构体变量的定义和初始化

struct Stu
{
    char name[20];//名字
    char tele[12];//电话
    char sex[10];//性别
    int age;//年龄
};
struct Stu s3;//创建全局结构体变量
int main()
{
    struct Stu s1 = {"zhuzhongyuan","13151732661","nan",22};//(定义)创建结构体变量s1并初始化
    printf("%s %s %s %d",s1.name,s1.tele,s1.sex,s1.age);
	return 0;
}

结构体内存对齐

现在我们深入讨论一个问题:计算结构体的大小。

这也是一个特别热门的考点:结构体内存对齐

#include<stdio.h>
//内存对齐
//结构体内存对齐
struct S2
{
	int a;
	char b;
	char c;
};
struct S1
{
	char b;
	int a;
	char c;
};
int main()
{
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	return 0;
}

结构体内存对齐的规则

  1. 结构体的第一个成员永远放在结构体起始位置偏移量为0的位置
  2. 结构体成员从第二成员开始,总是放在一个对齐数的整数倍处
  3. 对齐数是什么呢是编译器默认的对齐数和变量自身大小的较小值注意一下 linux没有默认对齐数vs下默认对齐数是8
  4. 结构体的总大小必须是各个成员的对齐数中最大那个对齐数的整数倍
  5. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

几个练习

为什么存在内存对齐

1.平台原因(移植原因)

不是所有的硬件平台都能访问任意地址上的任意数据,某些平台只能在某些地址某些特定类型的数据,否则抛出硬件异常

2.性能原因

数据结构(尤其是栈)应该尽可能地在自然边界上对齐,原因在于,为了访问未对齐的内存,处理器需要作两次内存访问,而对齐的访问仅需要一次访问

总体来说

结构体内存对齐就是拿空间换取时间的做法,形象的说就是浪费了内存,换来了方便

解决

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。

修改默认对齐数

vs默认对齐数是8

我们可以通过#pragma pack()来修改默认对齐数

默认设置对齐数是2的几次方

offsetof宏的实现

计算结构体中某变量相对于首地址的偏移

offsetof原格式

结构体传参

值传递

址传递

如何选择

1.函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

2.如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。

结论: 结构体传参的时候,要传结构体的地址。

位段

什么是位段

位段的声明和结构体类似,有两个不同

1.位段的成员必须是int,unsiged int 或 signed int

2.位段的成员后面有一个冒号和一个数字

位段的内存分配 位段的成员可以是int, unsigned int,signed int,或者是char(属于整形家族)类型位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段

位段的跨平台问题 int 位段被当成有符号数还是无符号数是不确定的。位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这个也是不确定的。 总结:

跟结构相比,位段可以达到同样的效果,可以很好的节省空间,但是有跨平台的问题存在。

位段的应用

枚举

如果我们没有对枚举常量进行初始化的话,他们是默认加一的

我们常量分为4种

1.字面常量

2.const修饰的常变量

3.#号定义的标识符常量

4.枚举常量

这里我们就讲枚举常量

枚举常量是不可以改的,只能初始化

那枚举怎么用呢

枚举的优点

我们可以使用 #define 定义常量,为什么非要使用枚举? 枚举的优点:

增加代码的可读性和可维护性和#define定义的标识符比较枚举有类型检查,更加严谨。防止了命名污染(封装)便于调试

而define是不可以的,因为define是完完全全替换的,在代码中看到GREEN什么的直接替换为1,代码中就没有GREEN的概念了,完完全全的替换

使用方便,一次可以定义多个常量 简易计算器

#include<stdio.h>
enum Option
{
	exit,
	add,
	sub,
	mul,
	div
};
void menu()
{
	printf("*********************\n");
	printf("****1.add   2.sub****\n");
	printf("****3.mul   4.div****\n");
	printf("****    0.exit   ****\n");
	printf("*********************\n");
}

int main()
{
	int input = 0;
	int a = 0;
	int b = 0;
	int c = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d",&input);
		printf("请输入两个操作数:>");
		scanf("%d%d", &a, &b);
		switch (input)
		{
		case add:
			c = a + b;
			printf("%d\n", c);
			break;
		case sub:
			c = a - b;
			printf("%d\n", c);
			break;
		case mul:
			c = a * b;
			printf("%d\n", c);
			break;
		case div:
			if (b == 0)
			{
				printf("分子不能为0\n");
				break;
			}
			else
			{
				c = a / b;
				printf("%d\n", c);
				break;
			}
		default:
			break;
		}
	} while (input);
	return 0;
}

联合(共用体)

联合类型的定义

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以
联合也叫共用体)。

联合类型的声明

联合的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)

判断当前机器的大小端存储【】

之前学过一个方法

#include<stdio.h>
int main()
{
	int a = 1; //0x 00 00 00 01
	//低 -------------> 高
	//01 00 00 00   小端存储
	//00 00 00 01   大端存储
	//想办法拿到a的第一个字节
	char* pc = (char*)&a;
	if (*pc == 1)
	{
		printf("小端存储");
	}
	else
	{
		printf("大端存储");
	}
	return 0;
}

现在学到共用体正好利用他的特殊情况

#include<stdio.h>
union Un
{
	char c;
	int i;
};
int main()
{
	union Un u = { 0 };
	u.i = 1;
	if (u.c == 1)
	{
		printf("小端存储");
	}
	else
	{
		printf("大端存储");
	}
	return 0;
}

联合大小的计算

联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

以上就是C语言编程C++自定义个性化类型的详细内容,更多关于C++自定义类型的资料请关注我们其它相关文章!

(0)

相关推荐

  • C语言自定义数据类型的结构体、枚举和联合详解

    结构体基础知识 首先结构体的出现是因为我们使用C语言的基本类型无法满足我们的需求,比如我们要描述一本书,就需要书名,作者,价格,出版社等等一系列的属性,无疑C语言的基本数据类型无法解决,所以就出现了最重要的自定义数据类型,结构体. 首先我们创建一个书的结构体类型来认识一下 struct Book { char name[20]; char author[20]; int price; }; 首先是struct是结构体关键字,用来告诉编译器你这里声明的是一个结构体类型而不是其他的东西,然后是Boo

  • C语言 数据类型详细介绍

    C 数据类型 在 C 语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统.变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式. C 中的类型可分为以下几种: 序号 类型与描述 1 基本类型: 它们是算术类型,包括两种类型:整数类型和浮点类型. 2 枚举类型: 它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量. 3 void 类型: 类型说明符 void 表明没有可用的值. 4 派生类型: 它们包括:指针类型.数组类型.结构类型.共用体类型和函数类型.

  • C语言菜鸟基础教程之自定义函数

    先动手编写程序: #include <stdio.h> int add(int x, int y) { int z = x + y; return z; } int main() { int a = 1; int b = 2; int c = add(a, b); printf("c = %d\n", c); return 0; } 运行结果: c = 3 程序分析: (1) 函数定义的形式为: 类型 函数名称(类型 形式参数,--) { 函数体 } (2) 对应于咱们的程

  • C语言自定义函数的实现

    函数是一段可以重复使用的代码,用来独立地完成某个功能,它可以接收用户传递的数据,也可以不接收.接收用户数据的函数在定义时要指明参数,不接收用户数据的不需要指明,根据这一点可以将函数分为有参函数和无参函数. 将代码段封装成函数的过程叫做函数定义. C语言无参函数的定义 如果函数不接收用户传递的数据,那么定义时可以不带参数.如下所示: dataType functionName(){ //body } dataType 是返回值类型,它可以是C语言中的任意数据类型,例如 int.float.char

  • C语言自定义类型详解(结构体、枚举、联合体和位段)

    目录 前言 一.结构体 1.结构体类型的声明 2.结构体的自引用 3.结构体变量的定义和初始化 4.结构体内存对齐 5.结构体传参 二.位段 1.位段的定义 2.位段的内存分配 3.位段的应用 三.枚举 1.枚举类型的定义 2.枚举的优点 3.枚举的使用 四.联合体(共用体) 1.联合体的定义 2.联合体的特点 3.联合体的大小计算 总结 前言 一.结构体 1.结构体类型的声明 当我们想要描述一个复杂变量--学生,可以这样声明. ✒️代码展示: struct Stu { char name[20

  • C语言自定义类型的保姆级讲解

    前言 在我们日常写代码时,经常会遇到结构体类型的使用,今天带读者了解结构体类型的使用. 一.初始结构体 在了解结构体之前,我们先来了解一下结构体的基础只是,结构体到底是什么? 结构是一些值的集合,这些值称为成员变量.结构的每个成员可以是不同类型的变量. 下面举一个例子: struct tag { menber_list; //成员列表 }variable_list; //变量列表 例如我们使用结构体描述一台电脑 struct computer { int price;//价格 char name

  • C语言编程C++自定义个性化类型

    目录 自定义类型 结构体 声明一个结构体类型 特殊声明 结构体自引用 结构体变量的定义和初始化 结构体内存对齐 结构体传参 位段 枚举 联合(共用体) 联合类型的定义 联合类型的声明 联合的特点 判断当前机器的大小端存储[] 自定义类型 结构体 结构是一些值的集合,这些值称为成员变量.结构的每个成员可以是不同类型的变量 声明一个结构体类型 //声明一个学生类型,是想通过学生类型来创建学生变量(对象) //描述学生就得有属性啥的.名字,电话,性别,年龄 struct Stu { char name

  • C语言中的自定义类型之结构体与枚举和联合详解

    目录 1.结构体 1.1结构的基础知识 1.2结构的声明 1.3特殊的声明 1.4结构的自引用 1.5结构体变量的定义和初始化 1.6结构体内存对齐 1.7修改默认对齐数 1.8结构体传参 2.位段 2.1什么是位段 2.2位段的内存分配 2.3位段的跨平台问题 2.4位段的应用 3.枚举 3.1枚举类型的定义 3.2枚举的优点 3.3枚举的使用 4.联合 4.1联合类型的定义 4.2联合的特点 4.3联合大小的计算 1.结构体 1.1结构的基础知识 结构是一些值的集合,这些值称为成员变量.结构

  • C语言深入探究自定义类型之结构体与枚举及联合

    目录 1.结构体 1.1结构体类型的声明 1.2结构的自引用 1.3结构体变量的定义和初始化 1.4结构体内存对齐 1.5结构体传参 1.6结构体实现位段(位段的填充&可移植性) 2.枚举 2.1枚举类型的定义 2.2枚举的优点 3.联合 3.1联合类型的定义 3.2联合的特点 3.3联合大小的计算 1.结构体 1.1结构体类型的声明 结构是一些值的集合,这些值称为成员变量.结构的每个成员可以是不同类型的变量 这里给大家举个列子演示一下: //定义一个学生的结构体 typedef struct

  • Go语言编程入门超级指南

    1.序言 Golang作为一门出身名门望族的编程语言新星,像豆瓣的Redis平台Codis.类Evernote的云笔记leanote等. 1.1 为什么要学习 如果有人说X语言比Y语言好,两方的支持者经常会激烈地争吵.如果你是某种语言老手,你就是那门语言的"传道者",下意识地会保护它.无论承认与否,你都已被困在一个隧道里,你看到的完全是局限的.<肖申克的救赎>对此有很好的注脚: [Red] These walls are funny. First you hate 'em,

  • java微信开发API第四步 微信自定义个性化菜单实现

    微信如何实现自定义个性化菜单,下面为大家介绍 一.全局说明 详细说明请参考前两篇文章. 二.本文说明 本文分为五部分:     * 工具类AccessTokenUtils的封装     * 自定义菜单和个性化菜单文档的阅读解析     * 菜单JSON的分析以及构建对应bean     * 自定义菜单的实现     * 个性化菜单的实现 微信自定义菜单所有类型菜单都给出演示 本文结束会给出包括本文前四篇文章的所有演示源码 工具类AccessTokenUtils的封装 在上文中关于AccessTo

  • 易语言编程基础数据类型变量及子程序

    目录 一. 易语言的数据类型 基本数据类型分为: 基本数据类型中的数值类型有包含了: 程序:数据类型转换 特殊数据类型 通用型数据类型: 库定义数据类型: 自定义数据类型: 内部组件数据类型: 二. 易语言中的变量 三. 易语言的资源表 四. 易语言中的运算符 五. 易语言中的子程序 一. 易语言的数据类型 易语言的数据类型可以分为基本数据类型和特殊数据类型 基本数据类型分为: ①   数值型 ②   逻辑型 ③   日期时间型 ④   文本型 ⑤   字节集型 ⑥   子程序指针型 基本数据类

  • Swift编程中的一些类型转换方法详解

    验证一个实例的类型'类型转换'在 Swift 语言编程中.它是用来检查实例类型是否属于特定超类或子类或其自己的层次结构定义. Swift 类型转换提供两个操作符:"is" 检查值的类型和 'as' 将类型值转换为不同的类型值. 类型转换还检查实例类型是否符合特定的协议一致性标准. 定义一个类层次结构 类型转换用于检查实例的类型或者它属于特定类型.此外,检查类和它的子类层次结构来检查并转换这些实例,使之作为一个相同的层次结构. 复制代码 代码如下: class Subjects {   

  • Android编程实现自定义渐变颜色效果详解

    本文实例讲述了Android编程实现自定义渐变颜色效果.分享给大家供大家参考,具体如下: 你是否已经厌恶了纯色的背景呢?那好,Android提供给程序员自定义渐变颜色的接口,让我们的界面炫起来吧. xml定义渐变颜色 首先,你在drawable目录下写一个xml,代码如下 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.

  • 混合语言编程—C#使用原生的Directx和OpenGL绘图的方法

    由于项目需要做一些图形展示,所以就想到了使用Directx和OpenGL来绘图,但项目准备使用C#来开发(大家比较熟悉C#),在网上看了相关的资料,有一些第三方的控件可用,试用了下,一运行就占了几百M的内存,而且也不知道是否稳定,教程也少,还不如直接使用原生的.在网上看的Directx和OpenGL的教程基本上都是C/C++的,找了很久也就找到相关介绍,只能自己研究下. 我以前做过C#和C++混合语言编程相关的东西,在C++实现一些C#不好实现的功能,C#动态调用DLL文件,所以也想到了用C++

  • C#编程实现自定义热键的方法

    本文实例讲述了C#编程实现自定义热键的方法.分享给大家供大家参考.具体实现方法如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Im

随机推荐