C 标准库 - <signal.h>和<stdarg.h>详解

目录

简介

库变量

库宏

库函数

实例

简介

库变量

库宏

实例


<signal.h>

简介

<signal.h> 是 C 语言标准库中的头文件之一,提供了对信号处理的支持。在 Unix 和类 Unix 系统中,信号是一种进程间通信机制,用于在进程之间传递异步事件的信息,例如错误、异常、中断等。<signal.h> 头文件定义了处理信号的相关函数和宏。

使用 <signal.h> 头文件时需要注意以下几点:

  • 信号处理函数应尽可能地简单,避免进行复杂或耗时的操作,因为它们通常是在不同上下文中执行的。
  • 信号处理函数应尽可能地避免调用不可重入函数,因为它们可能会被信号中断。
  • 一些信号是不可靠的,即不能保证它们是否会丢失。因此,在处理这些信号时需要格外小心。

总的来说,<signal.h> 提供了 C 语言中处理信号的基本机制,能够帮助程序员编写处理异步事件的代码。然而,由于信号处理涉及到并发和异步事件,因此编写可靠的信号处理代码是比较困难的,需要谨慎对待。

库变量

下面是头文件 signal.h 中定义的变量类型:

<signal.h> 头文件中定义了 sig_atomic_t 类型,用作信号处理程序中的变量类型。sig_atomic_t 是一个整数类型,在信号处理程序中可以作为原子操作的变量来访问。

这意味着,即使在处理异步信号的情况下,对 sig_atomic_t 类型的变量进行读取和写入操作都是原子的。原子操作是不可中断的操作,要么完全执行,要么完全不执行,不会被其他并发操作打断。这是确保在信号处理程序中对变量的访问是安全的关键。

sig_atomic_t 类型通常用于在信号处理程序中保存状态信息或标志,以指示信号的发生或某种事件的状态。由于它是原子的,可以保证对于多个并发的信号处理程序,对该类型变量的读取和写入不会出现竞态条件(Race Condition)导致的错误。

需要注意的是,sig_atomic_t 只保证对单个变量的原子性操作,而不是对于多个变量之间的原子操作。

总而言之,sig_atomic_t 类型是用于在信号处理程序中进行原子操作的变量类型,可以提供一定程度的线程安全性。

库宏

在 <signal.h> 头文件中定义了一些宏,这些宏在处理信号时会使用到。以下是其中的一些常用宏:

  • SIG_DFL:默认的信号处理程序。当信号的处理程序被设置为 SIG_DFL 时,表示使用系统默认的处理方式,通常是终止程序或忽略信号。
  • SIG_ERR:表示一个信号错误。当某个函数返回 SIG_ERR 时,表示出现了信号处理错误。
  • SIG_IGN:忽视信号。设置信号处理程序为 SIG_IGN 表示忽略该信号,即不做任何处理。

除了上述宏之外,<signal.h> 还定义了一系列以 SIG 开头的宏,用于表示各种条件下的信号码,例如:

  • SIGABRT:表示程序异常终止。
  • SIGFPE:表示算术运算出错,如除数为 0 或溢出。
  • SIGILL:表示非法函数映象,如非法指令。
  • SIGINT:表示中断信号,通常由用户按下 ctrl-C 产生。
  • SIGSEGV:表示非法访问存储器,如访问不存在的内存单元。
  • SIGTERM:表示发送给程序的终止请求信号。

这些宏可以与 signal 函数一起使用,用于指定信号的功能,例如设置信号处理程序、忽略信号或使用默认处理程序。

需要注意的是,这些宏的具体实现和行为可能会因操作系统和编译器的不同而有所差异。

库函数

<signal.h> 头文件中定义了用于设置和处理信号的函数。其中两个常用函数如下:

  • void (*signal(int sig, void (*func)(int)))(int):该函数用于设置一个函数来处理指定的信号 sig,即信号处理程序。func 参数是一个指向函数的指针,该函数表示在接收到信号时要执行的操作。如果 func 参数为 SIG_DFL,则表示使用系统默认的处理方式;如果为 SIG_IGN,则表示忽略该信号。该函数返回值为之前注册的信号处理程序的地址。
  • int raise(int sig):该函数用于发送指定的信号 sig 给当前进程。如果信号成功发送,则返回 0,否则返回非 0 值。该函数可以用于测试信号处理程序是否正确安装或测试信号是否被正确处理。

需要注意的是,虽然 signal 函数在大多数情况下可以用于注册信号处理程序,但是在一些特定的平台上可能存在不同的实现方式。为了编写可移植的代码,建议查阅特定平台的文档或参考相应的系统调用。

另外,由于信号处理程序通常在异步的上下文中执行,因此在编写信号处理程序时需要特别小心,避免出现竞态条件或其他不确定的行为。常见的编写技巧包括尽量使用原子操作、避免使用非可重入函数、不在信号处理程序中分配内存等。

实例

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>/* 信号处理程序 */
void sigint_handler(int sig) {printf("接收到中断信号 %d\n", sig);
}int main() {/* 注册 SIGINT 信号处理程序 */if (signal(SIGINT, sigint_handler) == SIG_ERR) {perror("无法注册 SIGINT 信号处理程序");exit(EXIT_FAILURE);}/* 发送 SIGINT 信号 */printf("发送中断信号...\n");if (raise(SIGINT) != 0) {perror("无法发送 SIGINT 信号");exit(EXIT_FAILURE);}printf("程序正常结束。\n");exit(EXIT_SUCCESS);
}

在上面的代码中,我们先定义了一个名为 sigint_handler 的函数,用于处理接收到的 SIGINT 信号。然后在 main 函数中,我们使用 signal 函数将 SIGINT 信号的处理程序设置为 sigint_handler。接着使用 raise 函数向进程发送 SIGINT 信号,并在控制台输出相应的信息。最后程序正常结束。 

让我们编译并运行上面的程序,这将产生以下结果:

发送中断信号...
接收到中断信号 2
程序正常结束。

<stdarg.h>

简介

stdarg.h 头文件定义了一个变量类型 va_list 和三个宏,这三个宏可用于在参数个数未知(即参数个数可变)时获取函数中的参数。 可变参数的函数通在参数列表的末尾是使用省略号(,...)定义的。

库变量

va_list 是 <stdarg.h> 头文件中定义的变量类型。

va_list 类型是一个用于存储可变参数信息的数据类型。通常情况下,我们会定义一个 va_list 类型的变量来操作可变参数函数。

具体使用时,通过调用 va_start 宏来初始化 va_list 变量,将其指向参数列表的第一个参数。然后,我们可以使用 va_arg 宏来获取 va_list 指针所指向的参数,并将指针移动到下一个参数的位置。最后,使用 va_end 宏来清理 va_list 变量。

这样,我们就可以在可变参数函数中遍历参数列表,根据需要进行操作。

库宏

下面是 <stdarg.h> 头文件中定义的宏及其描述:

  • void va_start(va_list ap, last_arg):该宏用于初始化 va_list 类型的变量 ap,将其指向参数列表中的第一个可变参数。last_arg 是最后一个传递给函数的已知固定参数,即省略号之前的参数。
  • type va_arg(va_list ap, type):该宏用于获取参数列表中类型为 type 的下一个参数,并将 va_list 指针 ap 移动到下一个参数的位置。返回值为获取到的参数值。
  • void va_end(va_list ap):该宏用于清理 va_list 类型的变量 ap,在使用完可变参数之后必须调用该宏。如果在从函数返回之前没有调用 va_end,则结果是未定义的。

这些宏一起配合使用,可以实现对可变参数函数中参数列表的遍历和操作。

需要注意的是,va_start 和 va_end 必须成对出现,且位于同一个函数中。va_arg 则用于获取具体的参数值,每次调用会将 va_list 指针移动到下一个参数的位置。

实例

#include <stdio.h>
#include <stdarg.h>// 计算可变参数列表中的整数之和
int sum(int num_args, ...) {va_list ap; // 定义一个用于存储可变参数信息的变量int sum = 0;va_start(ap, num_args); // 初始化 va_list 变量,num_args 是最后一个已知的固定参数for (int i = 0; i < num_args; i++) {int arg = va_arg(ap, int); // 获取下一个整型参数sum += arg;}va_end(ap); // 清理 va_list 变量return sum;
}int main() {int result = sum(4, 10, 20, 30, 40); // 调用可变参数函数printf("总和是 %d\n", result); // 输出结果return 0;
}

让我们编译并运行上面的程序,这将产生以下结果:

总和是 100

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

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

相关文章

【Java】面向对象程序设计 错题本

单选题 期中小测错题 1. Which specifier essentially declares a variable a global variable? A. protected B. static C. final D. default B global variable 是全局变量&#xff0c;也就是用 static 修饰的静态变量&#xff0c;因为它被所有实例所共享&#xff1b;…

SpringBoot Admin

前言 Spring Boot Admin 是一个管理和监控 Spring Boot 应用程序的开源项目&#xff0c;它提供了一个简洁的 Web 界面来监控 Spring Boot 应用程序的状态和各种运行时指标。Spring Boot Admin 可以帮助开发者快速了解应用程序的状态&#xff0c;并快速定位错误或性能问题。下面…

埃尔米特插值(hermite 插值) C++

埃尔米特插值 原理 #pragma once #include <vector> #include <functional> /*埃尔米特插值*/ struct InterpolationPoint {double x; // 插值点的横坐标double y; // 插值点的纵坐标double derivative; // 插值点的导数值// 默认构造函数InterpolationPoint() : x…

数据结构与算法之美学习笔记:24 | 二叉树基础(下):有了如此高效的散列表,为什么还需要二叉树?

目录 前言二叉查找树&#xff08;Binary Search Tree&#xff09;二叉查找树的时间复杂度分析解答开篇内容小结 前言 本节课程思维导图&#xff1a; 二叉查找树最大的特点就是&#xff0c;支持动态数据集合的快速插入、删除、查找操作。我们之前说过&#xff0c;散列表也是支持…

赛氪荣幸受邀参与中国联合国采购促进会第五次会员代表大会

11 月21 日 &#xff08;星期二&#xff09; 下午14:00&#xff0c;在北京市朝阳区定福庄东街1号中国传媒大学&#xff0c;赛氪荣幸参与中国联合国采购促进会第五次会员代表大会。 2022年以来&#xff0c;联合国采购杯全国大学生英语大赛已经走上了国际舞台&#xff0c;共有来自…

解析大型语言模型的训练、微调和推理的运行时性能

背景 这篇论文是截至目前为数不多的介绍大模型训练配套环境比对的论文&#xff0c;对于想要入门大模型训练同学是个不错的入门资料。比较了不同尺寸模型&#xff08;比较常用的7、13、70b&#xff09;&#xff0c;在不同型号gpu、训练框架、推理框架数据。结合自己实际工作需要…

C/C++数据结构之堆栈(Stack):理解、实现与运用

当我们讨论堆栈时&#xff0c;我们首先需要了解它的概念和基本原理。堆栈是一种后进先出&#xff08;Last In, First Out&#xff0c;LIFO&#xff09;的数据结构&#xff0c;它的操作主要包括压栈&#xff08;Push&#xff09;和弹栈&#xff08;Pop&#xff09;&#xff0c;以…

Git - 版本控制系统

目录 一、概述 配置用户信息 二、Git仓库 创建 本地仓库 git的三个区域 示例 Git文件状态 举例 三、区域使用 暂存区使用 版本库使用 文件忽略 四、分支 步骤 合并与删除 步骤 合并与提交 合并冲突 五、常用指令 六、Git远程仓库 使用步骤 克隆 同步 …

十七、SpringAMQP

目录 一、SpringAMQP的介绍&#xff1a; 二、利用SpringAMQP实现HelloWorld中的基础消息队列功能 1、因为publisher和consumer服务都需要amqp依赖&#xff0c;因此这里把依赖直接放到父工程mq-demo中 2、编写yml文件 3、编写测试类&#xff0c;并进行测试 三、在consumer…

HarmonyOS ArkTS 应用添加弹窗(八)

概述 在我们日常使用应用的时候&#xff0c;可能会进行一些敏感的操作&#xff0c;比如删除联系人&#xff0c;这时候我们给应用添加弹窗来提示用户是否需要执行该操作&#xff0c;如下图所示&#xff1a; 弹窗是一种模态窗口&#xff0c;通常用来展示用户当前需要的或用户必须…

富文本编辑器的实现与回显

文本编辑器实现-wangeditor 写之前记得安装wangeditor插件&#xff0c;到时候报错别赖我 import “wangeditor/editor/dist/css/style.css”; import { Editor, Toolbar } from “wangeditor/editor-for-vue”; defineOptions({name: "BaseEditor" });const mode …

关于在x64系统下使用MSSQL导入导出工具读取Excel报错的一个坑

从Excel导入数据到MSSQL是个高频需求。很多人&#xff0c;包括我&#xff0c;习惯打开ssms&#xff0c;从数据库点右键&#xff0c;任务&#xff0c;导入数据唤起导入操作&#xff0c;然后发现报错“未在本地计算机上注册 Microsoft.ACE.OLEDB.16.0提供程序”。 这个坑倒是很好…

高防CDN安全防护系统在业务方面的应用

在当今数字化的时代&#xff0c;网络安全问题日益严峻&#xff0c;保护网站和数据免受攻击变得至关重要。CDN安全防护系统作为一种有效的解决方案&#xff0c;受到了广泛关注。小德将向您介绍CDN安全防护系统的原理、应用场景以及使用方法&#xff0c;助您更好地保障网络安全。…

去除表格中的网格线

去除表格中的网格线 在excel中如何得到下图2的效果 点开视图&#xff0c;去除网格线 最后输出为图片

「L2C」型行业从线索到成交,听懂客户之「声」是关键

存量经营时代下&#xff0c;营销变得越来越难。无论是稳流量&#xff0c;或是促活跃&#xff0c;转化率就是难以提升。 相比传统快消行业&#xff0c;线索型&#xff08;L2C&#xff0c;Leads to Cash&#xff09;行业因为客单价高、决策周期长、用户触点分散等特性&#xff0…

CRM系统中的联系人是什么?如何进行联系人管理?

上手CRM系统前掌握专业术语是必要的功课&#xff0c;在第一次使用CRM系统时小编和大家一样&#xff0c;分不清楚线索、联系人、客户、商机之间的关系&#xff0c;今天我们就来着重分享一下CRM中联系人是什么&#xff1f;如何进行联系人管理&#xff1f; CRM系统联系人是指能够…

2023年国自然植物科学相关面上项目信息公布(小麦、大麦、棉花、大豆、玉米)

2024年申报国自然项目基金撰写及技巧http://mp.weixin.qq.com/s?__bizMzA4NTAwMTY1NA&mid2247575761&idx1&sn32dbacd3393f3b76a1e0668e4b8b3c89&chksm9fdd7c08a8aaf51ec31d4790067bb57751a09947eeb7e728b8c008d26b89adba37e0cab32a62&scene21#wechat_redi…

梨花声音课堂,真诚和情感展现家庭生活场景,易使观众产生共鸣

在为家庭剧的配音工作时&#xff0c;配音员要能够传递出剧中角色在日常生活中所经历的情感波动&#xff0c;以及家庭关系中的温情、矛盾和解决问题的过程。家庭剧着重描绘亲情纽带和人物间的真挚交往&#xff0c;因此配音的真实感和情感表达尤为重要。以下是针对家庭剧配音的几…

毕业设计2049网上选课系统JSP【程序源码+文档+调试运行】

摘要 本文详细介绍了一个网上选课系统的设计与实现过程。该系统主要分为学生用户、管理员和教师用户三个模块&#xff0c;涵盖了用户登录、在线选课、信息管理、密码修改等功能。通过对系统功能的分析&#xff0c;进行了数据库设计和界面设计&#xff0c;并进行了测试和优化。…

Java线程的学习

本来我以为这可能只是Java里的一小块知识点&#xff0c;但当我搜索自己关注的Up主的网课时&#xff0c;觉得还是开一个系列来记录好了。我的记录绝不仅仅是照搬课程中的内容&#xff0c;我会带上自己的理解以及示例代码、并且是按照本人的专业课老师上课的节奏来记录&#xff0…