【新手解答4】深入探索 C 语言:全局变量声明、全局函数声明 + 宏定义

C语言的相关问题解答

  • 写在最前面
  • 问题一:全局声明
    • 全局变量的声明
    • 全局函数的声明
  • 问题二:返回值&函数声明
    • 函数定义和返回值
    • 函数声明和函数体内的声明
    • 结论
  • 问题二延伸:优先采用全局声明
    • 原因
      • 1. 易于维护和查找
      • 2. 避免重复声明
      • 3. 保持代码的清晰和组织性
      • 4. 支持模块化编程
    • 在特殊情况下的内部声明
  • 问题三:宏定义
    • 宏定义的基本形式
    • 例子
    • 宏的特点

写在最前面

一位粉丝私信交流,回想起了当初的我C语言一题写一下午的,而且很多概念糊糊的不清楚。借助这次机会,整理了相关 C 语言中最常见而关键的疑惑,并对概念进行解答。

本篇博客的前身:
【新手解答1】深入探索 C 语言:变量名、形参 + 主调函数、被调函数 + 类和对象 + 源文件(.c 文件)、头文件(.h 文件)+ 库
【新手解答2】深入探索 C 语言:变量名、变量 + 函数声明 vs 函数定义 + main的声明 + 头文件和源文件的关系
【新手解答3】深入探索 C 语言:头文件提供必要的接口、源文件保持实现细节的私有性 + 进一步学习的方向 + 如何快速编写程序并最终能制作小游戏

如有不对的地方欢迎指出!好久没接触C了hh

问题一:全局声明

全局声明又是什么呢?

全局声明在编程中通常指的是在程序的任何地方都可以访问的变量或函数的声明。在 C 语言中,全局声明可以是全局变量的声明或者函数的声明。这些声明放在所有函数之外,通常放在源文件的顶部或者头文件中。这样做的目的是为了让这些变量或函数在整个程序中都是可见的和可用的。

全局变量的声明

全局变量在所有函数之外声明,通常在文件的开始处。它们在整个程序的执行期间都存在,并且在程序的任何地方都可以被访问和修改。

例子:

#include <stdio.h>int globalVar = 10; // 全局变量声明void display() {printf("Global variable: %d\n", globalVar);
}int main() {display();return 0;
}

在这个例子中,globalVar 是一个全局变量。它在 main 函数和 display 函数中都是可见的。

全局函数的声明

全局函数的声明意味着函数的原型在所有函数之外声明,这样在不同的源文件中的其他函数就可以调用这些函数。通常,函数的原型放在头文件中,然后在需要的源文件中包含这个头文件。

例子:

// math_functions.h
#ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_Hint add(int a, int b); // 函数声明#endif// math_functions.c
#include "math_functions.h"int add(int a, int b) {return a + b;
}// main.c
#include <stdio.h>
#include "math_functions.h"int main() {int result = add(5, 3);printf("Result: %d\n", result);return 0;
}

在这个例子中,add 函数在 math_functions.h 头文件中声明,然后在 math_functions.c 中定义。main.c 包含了 math_functions.h 头文件,所以它可以调用 add 函数。


全局声明使得变量和函数在程序的多个部分中都可以被访问。这对于需要在多个文件或函数间共享的数据和功能非常有用。然而,过度使用全局变量可能会导致代码难以维护,因为它们可以在程序的任何地方被改变,这可能导致预料之外的副作用。全局函数的使用则有助于代码的模块化和重用。

问题二:返回值&函数声明

(一个朋友说)返回由函数本身处理,而不是指向函数的声明
那假如一个函数的函数体中包含着一个函数声明,那这时函数声明,后面是否需要跟一个返回值来返回函数体?
哦,貌似找到答案了,返回值因为函数体存在而存在,因此,函数中无论引用什么声明之类的……都不会影响到返回值以及函数体本身,是这样的么?

是的,你的理解是正确的。在 C 语言中,函数的返回值是由函数自身的定义(函数体)决定的,而不是由函数的声明或函数体内部的其他声明决定的。让我更详细地解释这一点:

函数定义和返回值

  1. 函数定义(函数体):函数定义包含了函数的实现代码。它告诉编译器和程序如何执行该函数的特定任务。

  2. 返回值:函数定义还规定了该函数的返回类型。在函数体中,通常会有一个 return 语句来返回一个值,这个值的类型必须与函数声明的返回类型相匹配。

函数声明和函数体内的声明

  • 函数声明:函数声明告诉编译器函数的名称、返回类型和参数。声明本身不包含任何关于如何执行函数的信息。

  • 函数体内的声明:虽然在函数体内部声明另一个函数是不常见(也不推荐)的做法,但即使这样做了,它也不会影响到包含它的函数的返回值或行为。函数体内部的任何声明都是独立的,不会影响外围函数的返回行为。

结论

  • 一个函数的返回行为完全由该函数的定义(函数体内的代码)决定。这包括它返回什么类型的值,以及在何种条件下返回。

  • 函数体内部的其他声明(例如另一个函数的声明)不会影响该函数的返回行为。

  • 总是建议将函数的声明放在头文件或源文件的顶部,而不是在另一个函数的定义中。

你的理解是正确的,函数的行为和返回值完全由它自己的定义决定,与函数体内的其他声明无关。

问题二延伸:优先采用全局声明

唔,那如果有这类需要(一个函数体内声明另一个函数),会怎么办?
唔……我朋友说要优先采用全局声明

如果朋友提到“优先采用全局声明”,可能是指在编程实践中应该优先考虑将函数的声明放在全局范围内,也就是说,通常放在头文件中或者源文件的顶部。

在日常编程实践中,确实应该尽可能地将函数声明放在头文件或源文件的顶部,以提高代码的可维护性和清晰度。只有在有充分理由的情况下才考虑局部声明。

原因

“优先采用全局声明”这样做有几个重要的理由和好处:

1. 易于维护和查找

将函数声明放在全局范围(如头文件)使得这些函数可以被多个源文件共享。这样做的好处是,当需要修改函数原型或接口时,只需在一个地方进行更改,而不需要在多个文件中重复修改。

2. 避免重复声明

在 C 语言中,在同一个文件或代码范围内重复声明同一个函数是不必要的,也可能导致混淆。全局声明确保了每个函数只被声明一次。

3. 保持代码的清晰和组织性

将所有重要的函数声明放在一个集中的地方(如头文件)有助于保持代码的组织性和清晰性。这使得其他开发者(或未来的你)更容易理解程序的结构和可用的接口。

4. 支持模块化编程

全局声明支持模块化编程,使得代码更易于管理和重用。例如,你可以创建一个头文件,其中声明了一系列相关的函数,然后在需要这些功能的任何源文件中包含这个头文件。

在特殊情况下的内部声明

虽然一般推荐全局声明,但在某些特殊情况下,可能需要在函数体内部进行局部声明,比如声明局部函数或特定于某个功能的类型。这些情况通常比较少见,并且应谨慎使用以避免造成混淆。

问题三:宏定义

对了,查了一下宏的定义,字符串是宏体,标识符是宏名,预处理中会用宏体替换宏名,但这里的宏却仅仅指的是宏定义,那么宏声明呢?

在 C 语言中,宏主要是通过预处理指令 #define 来定义的。不像函数那样有声明和定义之分,宏通常只有定义,没有所谓的“宏声明”。宏定义在预处理阶段就被处理了,它们的作用是在编译之前,指示预处理器将所有宏名替换为对应的宏体。

它们是强大的工具,但也需要谨慎使用,因为不当的使用可能会导致代码维护和调试的困难。

宏定义的基本形式

宏定义的一般形式如下:

#define 宏名 宏体

这里,“宏名”是你希望定义的宏的名称,而“宏体”是当宏名在代码中出现时要被替换成的文本。

例子

  1. 定义常量

    #define PI 3.14159
    

    在这个例子中,每当预处理器遇到 PI,它都会将其替换为 3.14159

  2. 定义宏函数

    #define SQUARE(x) ((x) * (x))
    

    这里定义了一个宏函数 SQUARE,用于计算一个数的平方。在代码中使用 SQUARE(5) 时,它会被展开为 ((5) * (5))

宏的特点

  • 文本替换:宏仅仅是简单的文本替换工具,预处理器不会检查宏体的语法或者进行类型检查。

  • 没有类型:与函数不同,宏不涉及数据类型。

  • 编译前处理:宏是在编译前处理的,因此它们不占用程序运行时的内存。

  • 调试困难:由于宏只是在预处理阶段进行文本替换,所以在调试时可能会带来不便,因为宏在编译后的代码中不再可见。


希望这些解释能帮助更清晰地理解这些概念!如果还有其他疑问或需要进一步的解释,随时欢迎提问。

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

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

相关文章

AI生成技术威胁版权保护,水印技术和法律完善是关键/安圭拉小岛以.ai域名注册赚得3000万美元 |魔法半周报​

我有魔法✨为你劈开信息大海❗ 高效获取AIGC的热门事件&#x1f525;&#xff0c;更新AIGC的最新动态&#xff0c;生成相应的魔法简报&#xff0c;节省阅读时间&#x1f47b; &#x1f525;资讯预览 AI生成技术威胁版权保护&#xff0c;水印技术和法律完善是关键 Sam Altman对…

Web 安全之 X-XSS-Protection 详解

目录 什么是 X-XSS-Protection XSS 攻击概述 X-XSS-Protection 的值 工作原理 如何设置 X-XSS-Protection 头 示例说明 X-XSS-Protection 局限性 现代替代方案 小结 什么是 X-XSS-Protection X-XSS-Protection 是一个旨在启用或配置某些版本的 Internet Explorer、C…

1140. 最短网络,prim算法,模板题

1140. 最短网络 - AcWing题库 农夫约翰被选为他们镇的镇长&#xff01; 他其中一个竞选承诺就是在镇上建立起互联网&#xff0c;并连接到所有的农场。 约翰已经给他的农场安排了一条高速的网络线路&#xff0c;他想把这条线路共享给其他农场。 约翰的农场的编号是1&#xf…

webform使用ajax访问后端接口的两种方法

第一种方法&#xff1a;ajax前后端交互&#xff0c;前端使用这种传参方式&#xff1a;JSON.stringify({obj:JSON.stringify(json_obj)})&#xff0c;而后端使用这种接参方式&#xff1a;public static string mymethod(string obj)&#xff0c;注意前后端参数的名称必须相同。 …

记录一次如何查询mysql分库分表数据

一、前言 本次查询是在未知如何分库分表的情况下&#xff0c;对表数据进行查询&#xff0c;其中有的字段为JSON结构。需要提取JSON中某个字段的内容。 二、查询步骤 1、第一方式是将所有分表数据进行union all select * from apporder.ord_shopping_order union all sel…

vue跨域请求

vue.config.js devServer:{proxy:"http://localhost:8081"}main.js中定义 import axios from "axios"; axios&#xff0c; App.vue中引用 <template><Article/> </template><script> import Article from "/components/Ar…

才聚免费为你招聘,用人单位看过来!

才聚团队从1998年开始从事项目管理的推广工作&#xff0c;20多年来培训学员超30万人次&#xff0c;分布全国各地、服务企业超过5000家。拥有大批 PMP &#xff08;项目管理专业人员资格&#xff09; NPDP&#xff08;产品经理国际资格&#xff09; 软考 &#xff08;信息系统…

Python量化--多空策略:使用 Zipline 进行回测

我将向您展示多空策略以及 zipline 回测。这是一个编码教程,我将向您展示整个代码并解释每个单元格的作用。 让我们开始编码: from collections import defaultdict from time import time import warningsimport numpy as np import pandas as pdimport matplotlib.pyplot a…

五丶openlayer之LOD和分辨率

LOD是Levels of Detail的简写&#xff0c;用于根据当前的环境&#xff0c;渲染不同的图像&#xff0c;用于降低非重要的细节度&#xff0c;从而提高渲染效率&#xff0c;在电子游戏中经常运用&#xff0c;对于需要显示全球地图的GIS系统而言&#xff0c;更需要应用这项技术。 …

UE5学习(游戏存档,两种适应性的射线检测,时间膨胀)

游戏存档 0.建立游戏存档类 1.建立存档 命名要用规律&#xff0c;读档时根据命名调用 2.读取存档 这里是用存档时间&#xff08;秒&#xff09;验证是否有存档成功。 两种鼠标位置射线检测方法 两种适用性未使用大量项目验证&#xff0c;为个人观点 1.适用于游戏中 2.适用于…

Ubuntu20.04部署TVM流程及编译优化模型示例

前言&#xff1a;记录自己安装TVM的流程&#xff0c;以及一个简单的利用TVM编译模型并执行的示例。 1&#xff0c;官网下载TVM源码 git clone --recursive https://github.com/apache/tvmgit submodule init git submodule update顺便完成准备工作&#xff0c;比如升级cmake版本…

YOLOv8 onnx 文件推理多线程加速视频流

运行环境&#xff1a; MacOS&#xff1a;14.0Python 3.9Pytorch2.1onnx 运行时 模型文件&#xff1a; https://wwxd.lanzouu.com/iBqiA1g49pbc 密码:f40v 下载 best.apk后将后缀名修改为 onnx 即可模型在英伟达 T4GPU 使用 coco128 训练了 200 轮如遇下载不了可私信获取 代码…

生成XXX+年月日+几位递增数字的序列号

public String createAutoID(String tableNameKey) {//这里是 Redis key的前缀&#xff0c;如: sys:tabieId:表名 如果不需要去掉表名也可以String key MessageFormat.format("{0}:{1}:{2}", "sys","tableId",tableNameKey);//查询 key 是否存…

个人投资白银收益怎么样?

个人投资白银是可以带来丰厚的收益&#xff0c;但收益的具体情况取决于多种因素。以下是一些明确的答案和举例&#xff0c;帮助投资者更好地理解个人投资白银的收益情况。 白银市场的价格波动是决定投资收益的主要因素之一&#xff0c;白银价格受全球经济形势、地缘局势风险、…

Cesium 可视化深度纹理

Cesium 可视化深度纹理 // 创建纹理辅助器图元const textureHelper new TextureHelperPrimitive(viewer.scene)viewer.scene.primitives.add(textureHelper)viewer.scene.postRender.addEventListener(function () {const framebuffer viewer.scene.view.pickDepths[0]?.fra…

设计前中后队列 : 图解极简队列解法 [Deque + 纯数组](含进阶链表)

题目描述 这是 LeetCode 上的 「1670. 设计前中后队列」 &#xff0c;难度为 「中等」。 Tag : 「数据结构」、「双端队列」、「队列」、「链表」 请你设计一个队列&#xff0c;支持在前&#xff0c;中&#xff0c;后三个位置的 push 和 pop 操作。 请你完成 FrontMiddleBack 类…

easyexcel指定sheet页动态给行列加背景色

easyexcel&#xff0c;有多个sheet页&#xff0c;某些sheet页的行、列动态需要加背景色 import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.m…

了解FastSam:一个通用分割模型(草记)

想尝试这个FastSam的部署&#xff0c;但至今还没跑通&#xff0c;一个问题能带出一片问题&#xff0c;感觉挺心情挺郁闷的。后来和学长交流的时候&#xff0c;说那就是学少了&#xff0c;没必要急着将跑通它作为目的。也很有道理&#xff0c;这个任务还不太适合我当前的水平&am…

「Verilog学习笔记」信号发生器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 方波的实现&#xff0c;较为简单&#xff0c;只需要设置一个计数器&#xff0c;使输出保持10个时钟为0&#xff0c;跳变为20&#xff0c;再保持10个时钟。依次循环。可以按…

基于Webserver的工业数据采集控制

http协议 http简介 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写&#xff0c;是用于Web Browser&#xff08;浏览器&#xff09;到Web Server&#xff08;服务器&#xff09;进行数据交互的传输协议。 HTTP是应用层协议 HTTP是一个基于…