C语言不完全类型是什么?有什么用途?

news/2024/9/19 16:04:17

目录

1、不完全类型的概念

2、不完全类型的用途

3、不完全类型实践应用


1、不完全类型的概念

ISO(国际标准化组织(International Standard Organization))将C语言分为三个不同类型集合: 函数类型、对象类型和不完全类型,具体说明如下所示:

  • 函数类型:函数就是C语言的模块、一系列 C 语句的集合,有较强的独立性,能完成某个特定的功能,可以相互调用;
  • 对象类型:C语言的对象类型不是说面向对象编程,而是在内存中创建具有特定长度,有意义的类型,例如char、int、数组、结构体、指针等;
  • 不完全类型:不完全类型是指除了函数类型之外,大小不能被确定的类型。比如,声明了一个数组,但不给出数组的长度;声明了一个结构类型,但不给出结构体的定义,只告诉编译器这是一个结构体。在最终你还是必须得给出完整的定义,否则编译器在编译单元中都找不到不完全类型的完整定义信息的话就会报错。

C语言所有数据类型如下图所示:

在C99标准中对不完全类型描述如下:

The void type comprises an empty set of values; it is an incomplete type that cannot be completed. (C99 6.2.5/19)

An array type of unknown size is an incomplete type. It is completed, for an identifier of that type, by specifying the size in a later declaration (with internal or external linkage). A structure or union type of unknown content (as described in 6.7.2.3) is an incomplete type. It is completed, for all declarations of that type, by declaring the same structure or union tag with its defining content later in the same scope.(C99 6.2.5/22)

总结讲,C/C++中不完全类型有三种不同形式:void、未指定长度的数组以及具有非指定内容的结构和联合。void类型与其他两种类型不同,因为它是无法完成的不完全类型,并且它用作特殊函数返回和参数类型。

不完全类型是暂时没有完全定义好的类型,编译器不知道这种类型该占几个字节的存储空间,例如以下定义方式:

int str[]; //不完全类型数组str定义…int str[10]; //定义str数组完整的类型信息

再举个例子,在头*.h文件中声明结构:typedef struct __list *list_t;,最终在*.c文件中定义如下:

struct __list {struct __list *prev;struct __list *next;viud   *data;};

此时,结构体变量*list_t就属于不完全类型,不完全类型不包含具体的类型信息,所以在未完整定义前不能通过sizeof来获知大小,并且不完全类型定义不适合局部变量。

2、不完全类型的用途

不完全类型的用途主要为以下三点:

1、提高代码灵活性。在*.h头文件中声明的数组,不清楚具体使用场景应该需要多大,在*.c中使用数组前再完整定义,就可以很方便的更改数组的大小,也不用再去修改头文件。

2、两个结构体需要相互指向,唯一能够实现的方式就是不完全结构,如下所示:

struct a { struct b *pb; };struct b { struct a *pa; };

3、实现抽象模型的封装,降低程序模块之间的耦合,防止用户直接访问结构成员,破坏内部抽象数据类型。这样可以强制用户通过接口规则访问,隐藏内部实现细节,降低沟通成本。

3、不完全类型实践应用

举个例子,项目开发中需要用到环形缓存(一种用于表示一个固定尺寸、头尾相连的缓冲区的数据结构,适合缓存数据流),于是小伙伴将这个任务交给了你。然后你实现了ring_buffer.c,并在ring_buffer.h头文件中定义了实现功能用的数据结构和接口,初次程序设计如下所示:

typedef struct _ring_buffer_type
{uint8_t *phead;               uint8_t *ptail;                 uint8_t *pread;                uint8_t *pwrite;               size_t   size;                volatile size_t counts;          
}rcb_t;/* 构建并初始化一个环形缓存 */
err_t  ring_buffer_init(uint8_t *pbuffer, size_t size);/* 向缓存中写数据 */
err_t  ring_buffer_write(rcb_t *const p_rcb, uint8_t *pdata, size_t len);/* 从缓存中读数据 */
err_t  ring_buffer_read(rcb_t *const p_rcb, uint8_t *pdata, size_t len);/* 检查缓存已使用的字节数 */
err_t  ring_buffer_check(rcb_t *const p_rcb, size_t *len);

经过测试,功能实现很好,任务顺利完成。为了屏蔽功能实现细节你将模块封装成了库,信心十足的交给了小伙伴使用。但是你的伙伴却投来了鄙视的目光,说你的实现的功能有问题,于是你们一起检查他的代码,你发现他写了如下代码:

ring_buffer_write(&buf_rcb, pdata, 10);buf_rcb. pwrite += 10;buf_rcb.counts += 10;

于是你不解的质问小伙伴,为什么要动内部的数据,但小伙伴却说,往里面写入了数据,应该要修改指针啊。你认为的事,小伙伴想的却不一样。

然后为了不让别人动你内部的数据,于是你在头文件ring_buffer.h中把结构定义改成了:

typedef struct _ring_buffer_type rcb_t;

并将结构的定义放在了ring_buffer.c中:

struct _ring_buffer_type
{uint8_t *phead;              uint8_t *ptail;                 uint8_t *pread;                 uint8_t *pwrite;               size_t   size;                  volatile size_t counts;         
};

从此之后,内部的细节都被隐藏了,封装成库之后别人再也不清楚内部的数据结构了,只能严格按照接口的要求进行调用,自然无法修改你的内部数据了。并且,以后修改内部实现也更方便了,甚至外部的接口都不需要做更改。

从用户的角度,知道的细节越少越好,即减少了记忆的成本,也避免了一些不必要的麻烦。


本文参考:麦克泰技术文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pgtn.cn/news/18653.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

PCL:k-d tree 1 讲解

1.简介 kd-tree简称k维树,是一种空间划分的数据结构。常被用于高维空间中的搜索,比如范围搜索和最近邻搜索。kd-tree是二进制空间划分树的一种特殊情况。(在激光雷达SLAM中,一般使用的是三维点云。所以,kd-tree的维度…

LabVIEW图像灰度分析与变换(基础篇—4)

目录 1、图像灰度分析 1.1、直方图分析 1.1.1、灰度图像直方图分析 1.1.2、彩色图像直方图分析 1.2、线灰度曲线分析 1.3、图像线灰度均值分析 1.4、图像形心和质心分析 1.5、图像灰度定量描述分析 2、图像灰度变换 1、图像灰度分析 图像灰度分析是图像分析中最基本的…

opencv线性插值(上采样)

1、调用opencv的API pyrUp(src, dst, Size(src.cols * 2, src.rows * 2)); pyrUp:API详解 这里的up是指将图像的尺寸变大,所以原始图像位于图像金字塔的顶层。 首先将当前层图像的宽高扩大2倍,插入的行和列位于偶数行或偶数列,这…

Python:KNN

KNN 理解: 导语:商业哲学家 Jim Rohn 说过一句话,“你,就是你最常接触的五个人的平均。”那么,在分析一个人时,我们不妨观察和他最亲密的几个人。同理的,在判定一个未知事物时,可以…

毕业设计So Easy:基于Java语言西餐厅点餐系统

目录 1、选题的背景及研究意义 2、研究内容及设计思想 3、系统功能分析 3.1、牛霸王总台管理员对功能的需求 3.2、客人对功能的需求 3.3、系统具有的整体功能 4、系统总体设计 4.1、系统流程结构设计 4.1.1、餐台消费功能 4.1.2、牛霸王总台管理功能 4.2、系统模块设…

OpenCV Mat类型的遍历与访问

1、指针遍历 uchar *data1 M.ptr<uchar>(0);只有“()”需要uchar类型的指针接收 uchar data2 M.ptr<uchar>(1)[2]; uchar data3 M.ptr<uchar>(2)[3]; 注意&#xff1a; 1.图像的指针是从(0&#xff0c;0)位置开始&#xff0c;并且“()”代表行&am…

电子产品PCB电路板散热的方法

电子设备工作时都会产生一定的热量&#xff0c;从而使设备内部温度迅速上升&#xff0c;如果不及时将该热量散发出去&#xff0c;持续升温&#xff0c;器件就会因过热而失效&#xff0c;电子设备的可靠性能就会下降。因此&#xff0c;对PCB电路板进行很好的散热处理是非常重要的…

PCL :K-d tree 2 结构理解

K-d tree 基础思路&#xff1a;&#xff08;先看之前的KNN思想&#xff0c;更容易理解&#xff09; 导语&#xff1a;kd 树是一种二叉树数据结构&#xff0c;可以用来进行高效的 kNN 计算。kd 树算法偏于复杂&#xff0c;本篇将先介绍以二叉树的形式来记录和索引空间的思路&am…