如何分析C语言中的声明

news2024/9/23 16:15:07

声明是C语言中一个非常基础但重要的部分,无论是阅读他人的代码,还是排查编译报错,正确理解声明都会对我们有莫大的帮助。
有的人可能会说声明不是很简单吗?

小A说,看,我声明了一个整型变量:

int a;

小B说,瞧,我声明了一个函数:

int func(void);

我想大家理解上面的声明肯定是手拿把掐,轻而易举。

那么,下面几个声明呢?

int* arr[10];
int (*arr_ptr)[10];
int *func(int a);
int (*func_ptr)(int a);

以及这个呢?

int (*func_arr[5])(int a, int b);

如果你有点拿不准了,那就往下看吧,本文的目的就是给大家分享一下解析声明的方法,从而使得各位更好地理解 C 语言中的声明。

一、认识声明

首先让我们来看下声明的组成,一般来说,声明具体如下格式:

声明说明符 声明符;

声明说明符描述的是声明的数据项的性质,声明符描述的则是数据项的名字,并且描述了数据项性质的额外特点。

声明说明符有三大类:

  • 存储类型: autostaticexternregister
  • 类型限定符: constvolatile
  • 类型说明符: voidcharshortint

为了让大家便于理解,本文只讨论仅带类型说明符的声明,我想这是大家最熟悉的部分,存储类型与类型限定符我们以后再讨论。

接下来,让我们来认识一下声明符:声明符是由标识符、*[]()组成的。

  • 标识符:声明的变量或者函数的名字

    int a;
    

    这是最简单的声明符,其中a是标识符,由于没有其他符号,因此这个标识符a就是声明符。

  • *:如果在标识符前加一个*号,那么这个声明符表示指针

    int *p;
    
  • []:如果在标识符后加一个[],那么这个声明符表示数组

    int arr[10];
    
  • (): 如果在标识符后加一个(),那么这个声明符表示函数

    int add(int a, int b);
    

上面列出的几个声明符都很简单,但是我们在实际工作中遇到的声明符往往是标识符、*[]()的组合,也就是复杂声明符。接下来,让我们来看看如何分析复杂声明符。

二、声明的解析规则

有两条简单的规则可以帮助我们理解所有的声明,好的,划重点了:
第一条规则:由内而外

这条规则的含义就是,首先定位声明中的标识符,并由此开始解析

第二条规则:遇事不决找括号

当我们运用第一条规则找到标识符后,我们往往会发现标识符的左右两边有其他符号,这时候我们就会面临一个选择:向左走?向右走?

第二条规则为我们指明了方向,那就是找括号,即先()[],再*

举个栗子,让我们来分析如下声明:

int* arr[10];

根据第一条规则,我们首先找到标识符arr,然后从此处开始解析。

我们观察到在arr的左边是*,右边则是[10],那么arr是指针还是数组呢?

让我们运用第二条规则,先将arr[10]进行组合,这么一来**,arr的性质就确定了,它是一个数组**。

既然它是一个数组,那么就需要说明数组元素的类型和数量,数量我们已经知道了,10个,那么数组元素是什么类型呢?

根据第二条规则,接下来要解析*了,这说明数组元素的类型是指针,那么是什么类型的指针呢?int因此,我们知道了数组元素的类型是整型指针

综合起来,arr是一个包含10个元素的数组,每个元素的都是整型指针。

接着,我们来解析这条声明:

int *func(int a);

同样的,首先找到标识符,func,然后观察func的两边,发现左边是*,右边是(int a)

那么根据第二条规则,我们应该先将func(int a)结合,如此一来,func的性质就确定了,它是一个函数

既然是函数,那就要有参数和返回类型,根据(int a)我们可以知道,这个函数的接受一个整型参数。

对于返回类型,我们可以通过解析*得知,该函数的返回类型是一个指针,而指针的类型则是int,即整型指针。

综合起来,func是一个函数,它接收一个整型参数,返回类型是整型指针。

三、攻克复杂声明符

大家估计看出来了,第二条规则其实就是优先级的运用,因为()[]的优先级比*更高,所以我们先解析()[],再解析*

但是我们知道,()可以改变优先级,比如下面的声明:

int (*func_ptr)(int a, int b);

在上面的声明中,标识符func_ptr的左边是*,右边是(int a, int b),按照规则,应该先将func_ptr(int a, int b)结合,从而将func_ptr定性为函数。

但是,func_ptr*()包了起来,因此优先级被提高了,所以我们要先将func_ptr*号进行结合,因此func_ptr应该被定性为指针。

接着,我们要解析(int a, int b),从而可以确定func_ptr指向的是一个接受两个整型参数的函数,最后根据开头的int确定函数的返回值为整型。

综合起来就是,func_ptr是一个指向函数的指针,该函数接受两个整型参数的函数,返回类型是整型。

这种指针,我们一般叫它函数指针。

好了,有了以上经验,我们可以来解析本文的最终Boss了:

int (*func_arr[5])(int a, int b);

解析步骤如下:

  1. 找到标识符func_arr
  2. func_arr左边是*,右边是[5],因此先将func_arr[5]结合,从而将func_arr定性为数组,元素个数为5
  3. func_arr[5]的左边是*,右边是(int a, int b),但是func_arr[5]*被()包起来了,所以先解析*,从而确定数组的元素的类型是指针
  4. 接下来解析(int a, int b),可以确定指针指向的是一个接收两个整型参数的函数
  5. 最后根据开头的int确定函数的返回类型是整型

综合起来,func_arr是一个包含5个元素的数组,每个数组元素都是函数指针,指向的函数接受两个整型参数,返回类型是整型。

结语

希望通过本文的实例分析,可以帮助大家更好地理解和应用 C 语言中的各种声明语句。
若有错漏之处,欢迎大家交流指正~

最后,欢迎大家关注我的公众号《嵌入式3分钟》,一起学习嵌入式!
在这里插入图片描述

参考文献

[1] K.N.King, C语言程序设计:现代方法(第2版), 吕秀锋, 黄倩译,人民邮电出版社, 2010.

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

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

相关文章

htsjdk SamReader接口介绍

SamReader 是 htsjdk 库中的一个接口,用于读取和解析 SAM(Sequence Alignment/Map)和 BAM(Binary Alignment/Map)格式的文件。htsjdk 是一个广泛使用的 Java 库,提供了处理高通量测序数据的工具,SamReader 是其中的一个核心接口。 SamReader 接口介绍 SamReader 主要用…

也开发一点自己的agent框架

换了一份工作,抽空写一篇文章。 前面说自己看了ja-netfilter,这个作者肯定是个厉害的人,但是在项目工程化方面,做出来的东西未必好用是真的,不是diss别人,而是他的插件接口还是指令集的。说实话&#xff0c…

TCP BBR 数学模型完整版

今天顺带加入了 bbr 的所有状态和所有流程,获得以下的方程组: C Bltbw,R RtProp,T_r ProbeRTT 周期,g1 Startup gain,g2 ProbeBW gain。设 x estimated bandwidth,r round trip time&am…

【STM32】C语言基础补充

学习过程中发现自己好些需要用到的C语言语法、特征都不太熟练了,特意记录一下,免得忘记了,以后遇到了新的也会继续更新 目录 1 全局变量 2 结构体 3 静态变量 4 memset()函数 5 使用8位的存储器存16位的数 1 全局变量…

vue3 Props的用法(父传子)

在 Vue 3 中,Props(属性)用于在组件之间传递数据。 Props的作用 传参:Props 允许父组件向子组件传递数据。类型检查:Vue 允许在定义 Props 时指定数据的类型,这有助于在开发过程中进行类型检查&#xff0…

Nextjs(App Router) 开发记录

最近业余在开发一款智能助理产品,记录开发过程中的一些问题以备忘,也是帮其他人防坑。 主要技术栈 本项目采用了前沿的技术栈来构建一个高性能且可维护的应用。选择了 Nx 作为构建管理和单一代码库解决方案,通过模块化和插件系统来扩展和优…

开源的个人独立博客Moments社交优化项目源码

开源的个人独立博客Moments社交优化项目源码,为你提供了一个与关注的博客作者和读者互动的全新方式,让你的博客体验更加丰富和充实。 Moments的核心目标是通过整合各种订阅源,如RSS和Atom,将你感兴趣的博客转化为一个个人朋友圈。…

日志排查——linux

目录 介绍步骤 介绍 /var/log/wtmp:记录登录进入、退出、数据交换、关机和重启,即last。 /var/log/cron:记录与定时任务相关的日志信息。 /var/log/messages:记录系统启动后的信息和错误日志。 /var/log/apache2/access.log&a…

你不知道的console方法

JavaScript为我们提供了一个内置的调试工具,即控制台(console),使开发人员能够测试、调试和与他们的网页进行交互。JavaScript的控制台对象中有几种可用的方法,每种方法都有不同的用途。本文将讨论这些方法,并提供它们的使用示例。…

计算机毕业设计 学院网站 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

Linux中解决 zfs 安装后无法加载和使用,报错类似如下:modprobe: FATAL: Module zfs not found.

Linux中解决 zfs 安装后无法加载和使用,报错类似如下:modprobe: FATAL: Module zfs not found. # modprobe zfs modprobe: FATAL: Module zfs not found.解决办法: yum remove zfs spl kmod-zfs -yyum update -y --skip-brokenos_v$(cat /et…

文献翻译什么软件好?文献翻译全文软件推荐这5个

处暑已过,秋风渐起,知识的田野也迎来了收获的季节。在学术研究的旅途中,我们常常需要跨越语言的界限,探寻远方的智慧。 每当面对厚重的外文文献,应该如何快速准确地转化为可读的中文呢?其实只要选择一款高…

加速指南:如何使用Kimi提升论文写作效率?

在学术研究领域,撰写论文是一项基础且关键的任务,它要求作者不仅要有扎实的专业知识,还要具备高效的信息处理能力和清晰的表达技巧。学术写作是一个复杂的过程,涉及多个阶段:从选题、资料搜集、论文结构设计&#xff0…

STM32(五):定时器——输出比较

定时器输出比较功能:输出PWM波形 OC(Output Compare)输出比较 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。 每个高级定时器和通用定时器…

【硬件模块】红外跟随避障模块

红外跟随避障模块实物图 红外避障模块不断发射红外信号,当红外信号: 有反射回来,OUT 输出低电平,输出指示灯(绿灯)亮; 没反射回来,OUT 输出高电平,输出指示灯&#xff08…

tcp通信以及wireshark抓包

loop: //本地回环测试 tcp在传输时,有可能就会将两次发送的内容粘到一起,这是由于tcp的第三个特点:字节流式传输。它不一定会将两次发送出来的数据进行严格区分。这种现象在tcp链接中叫粘包。 但是socket在底层发送东西的时候是会在一段时间…

【微信小程序】使用 npm 包 - API Promise化-- miniprogram-api-promise

1. 基于回调函数的异步 API 的缺点 默认情况下,小程序官方提供的异步 API 都是基于回调函数实现的,例如,网络请求的 API 需要按照如下的方式调用: 缺点:容易造成回调地狱的问题,代码的可读性、维护性差&a…

I2C软件模拟与Delay寄存器延迟函数

环境 芯片:STM32F103ZET6 库:来自HAL的STM32F1XX.H 原理图 有图可知SCL和SDA两条线接到了PB10和PB11 Driver_I2C.h #ifndef __DRIVER_I2C #define __DRIVER_I2C#include "stm32f1xx.h" #include "Com_Delay.h" // 定义拉高SCL引脚的宏操作 #…

【电子数据取证】应用程序提取及固定

文章关键词:电子数据取证、手机取证、计算机取证、计算机仿真、云取证 一、前言 在数字化时代,电子数据已成为现代社会不可或缺的一部分,它不仅记录着个人的日常生活轨迹,也承载着企业运营的核心信息,更在司法体系中…

Nginx知识详解(理论+实战更易懂)

目录 一、Nginx架构和安装 1.1 Nginx 概述 1.1.1 nginx介绍 1.1.2 Nginx 功能介绍 1.1.3 基础特性 1.1.4 Web 服务相关的功能 1.2 Nginx 架构和进程 1.2.1 Nginx 进程结构 1.2.2 Nginx 进程间通信 1.2.3 Nginx 启动和 HTTP 连接建立 1.2.4 HTTP 处理过程 1.3 Nginx …