【Linux应用编程实战】常见函数应用

news2024/11/15 17:59:53

介绍一些Linux应用编程实战遇到的,常见要用的函数,进行概况总结。

目录

main()

lseek()
poll()

  1. struct pollfd 结构体
  2. 返回值
  3. 典例

mmap()

munmap()

ioctl()

main 函数

Linux 应用程序中,main 函数也是作为应用程序的入口函数存在,main 函数的形参一般会有两种写法

//示例代码 1.4.1 main 函数写法之无传参
int main(void)
{
	 /* 代码 */
}
//示例代码 1.4.2 main 函数写法之有传参
int main(int argc, char **argv)
{
	 /* 代码 */
}

/*	
int argc:		表示传入参数的个数,即命令行参数的数量,包括应用程序自身**路径**和**程序名**;。
char **argv:	是一个指向参数数组的指针,每个元素是一个指向参数字符串的指针
*/
例:运行当前目录下的 hello 可执行文件,并且传入参数,如下所示:
./hello 112233
那么此时参数个数为 2,并且这些参数都是作为字符串的形式传递给 main 函数:
argv[0]等于"./hello"
argv[1]等于"112233"
有传参时 main 函数的写法并不只有这一种

lseek函数

  • 功能:设置当前读写位置

  • 对于打开的文件,系统都会记录读写位置偏移量,记录文件当前的读写位置;

  • 调用 read()或 write()函数对文件进行读写操作时,从当前读写位置(起始位置)偏移量开始进行数据读写

函数原型与头文件

/*man 2 lseek*/
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
函数参数

fd: 文件描述符。

offset: 偏移量,以字节为单位。

whence: 用于定义参数 offset 偏移量对应的参考值,该参数为下列其中一种(宏定义):

SEEK_SET:读写偏移量将指向 offset 字节位置处(从文件头部开始算);

SEEK_CUR:读写偏移量将指向当前位置偏移量 + offset 字节位置处,offset 可以为正、也可以为负,如果是正数表示往后偏移,如果是负数则表示往前偏移;

SEEK_END:读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,如果是正数表示往后偏移、如果是负数则表示往前偏移。

返回值

成功将返回从文件头部开始算起的位置偏移量(字节为单位),也就是当前的读写位置;发生错误将返回-1。

典例

if (0 > lseek(pfd.fd, 0, SEEK_SET)) //将读位置移动到头部

poll函数

  • 与 select()函数很相似,但函数接口有所不同;
    • select()中,提供三个 fd_set 集合,在每个集合中添加我们关心的文件描述符;
    • poll()中,则需构造一个 struct pollfd 类型数组,每个数组元素指定一个文件描述符以及我们对该文件描述符所关心的条件(数据可读、可写或异常情况)

原型

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
/*
参数:
	fds:指向一个 struct pollfd 类型的数组,数组中的每个元素都会指定一个文件描述符以及我们对该文件
描述符所关心的条件,稍后介绍 struct pollfd 结构体类型。
	nfds:参数 nfds 指定了 fds 数组中的元素个数,数据类型 nfds_t 实际为无符号整形。
	timeout:该参数与 select()函数的 timeout 参数相似,用于决定 poll()函数的阻塞行为,具体用法如下:
		⚫ 如果 timeout 等于-1,则 poll()会一直阻塞(与 select()函数的 timeout 等于 NULL 同),			直到 fds数组中列出的文件描述符有一个达到就绪态或者捕获到一个信号时返回。
		⚫ 如果 timeout 等于 0,poll()不会阻塞,只是执行一次检查看看哪个文件描述符处于就绪态。
		⚫ 如果 timeout 大于 0,则表示设置 poll()函数阻塞时间的上限值,意味着 poll()函数最多阻塞			   timeout毫秒,直到 fds 数组中列出的文件描述符有一个达到就绪态或者捕获到一个信号为止。
struct pollfd 结构体
struct pollfd {
 int fd; 		/* file descriptor */
 short events; 	/* requested events */
 short revents; /* returned events */
};
  • fd 是一个文件描述符,struct pollfd 结构体中的 events 和 revents 都是位掩码

  • 调用者初始化 events 来指定需要为文件描述符 fd 做检查的事件

    当 poll()函数返回时,revents 变量由 poll()函数内部进行设置,用于说明文件描述符 fd 发生了哪些事件(注意,poll()没有更改 events 变量),我们可以对 revents 进行检查,判断文件描述符 fd 发生了什么事件。

  • 应将每个数组元素的 events 成员设置为表 13.2.1 中所示的一个或几个标志,多个标志通过位或运算符( | )组合起来,通过这些值告诉内核我们关心的是该文件描述符的哪些事件

    返回时,revents 变量由内核设置为表 13.2.1 中所示的一个或几个标志:

在这里插入图片描述

第一组标志(POLLIN、POLLRDNORM、POLLRDBAND、POLLPRI、POLLRDHUP)与数据可读相关;
第二组标志(POLLOUT、POLLWRNORM、POLLWRBAND)与可写数据相关;
第三组标志(POLLERR、POLLHUP、POLLNVAL)是设定在 revents 变量中用来返回有关文件描述符的附加信息,
如果在 events 变量中指定了这三个标志,则会被忽略。
  • 如果我们对某个文件描述符上的事件不感兴趣,则可将 events 变量设置为 0;

  • 另外,将 fd 变量设置为文件描述符的负值(取文件描述符 fd 的相反数-fd),将导致对应的 events 变量被 poll()忽略,并且 revents变量将总是返回 0,这两种方法都可用来关闭对某个文件描述符的检查。

在实际应用编程中,一般用的最多的还是 POLLIN 和 POLLOUT。

返回值

poll()函数返回值含义与 select()函数的返回值是一样:

⚫ 返回-1 表示有错误发生,并且会设置 errno。
⚫ 返回 0 表示该调用在任意一个文件描述符成为就绪态之前就超时了。
⚫ 返回一个正整数表示有一个或多个文件描述符处于就绪态了,
	返回值表示 fds 数组中返回的 revents变量不为 0 的 struct pollfd 对象的数量。

典例

使用 poll()函数来实现 I/O 多路复用操作,同时读取键盘和鼠标;

					/*示例代码 13.2.3 使用 poll 实现同时读取鼠标和键盘*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
    
#define MOUSE "/dev/input/event3"
    
int main(void)
{
     char buf[100];
     int fd, ret = 0, flag;
     int loops = 5;
     struct pollfd fds[2];
    
     /* 打开鼠标设备文件 */
     fd = open(MOUSE, O_RDONLY | O_NONBLOCK);
     if (-1 == fd) 
     {
         perror("open error");
         exit(-1);
     }
    
     /* 将键盘设置为非阻塞方式 */
     flag = fcntl(0, F_GETFL); //先获取原来的 flag
     flag |= O_NONBLOCK; //将 O_NONBLOCK 标准添加到 flag
     fcntl(0, F_SETFL, flag); //重新设置 flag
    
     /* 同时读取键盘和鼠标 */
     fds[0].fd = 0;
     fds[0].events = POLLIN; //只关心数据可读
     fds[0].revents = 0;
     fds[1].fd = fd;
     fds[1].events = POLLIN; //只关心数据可读
     fds[1].revents = 0;
     while (loops--) 
     {
         ret = poll(fds, 2, -1);
         if (0 > ret) 
         {
             perror("poll error");
             goto out;
         }
         else if (0 == ret) 
         {
             fprintf(stderr, "poll timeout.\n");
             continue;
         }

         /* 检查键盘是否为就绪态 */
         if(fds[0].revents & POLLIN) 
         {
             ret = read(0, buf, sizeof(buf));
             if (0 < ret)
                printf("键盘: 成功读取<%d>个字节数据\n", ret);
         }

         /* 检查鼠标是否为就绪态 */
         if(fds[1].revents & POLLIN) 
         {
             ret = read(fd, buf, sizeof(buf));
             if (0 < ret)
             printf("鼠标: 成功读取<%d>个字节数据\n", ret);
         }
     }
    out:
     /* 关闭文件 */
     close(fd);
     exit(ret);
}

struct pollfd 结构体的 events 变量和 revents 变量都是位掩码,所以可以使用"revents & POLLIN"按位与的方式来检查是否发生了相应的 POLLIN 事件,判断鼠标或键盘数据是否可读

在这里插入图片描述

总结
  • 在使用 select()或 poll()时需要注意一个问题:

    当监测到某一个或多个文件描述符成为就绪态(可以读或写)时:

    需要执行相应的 I/O 操作,以清除该状态,否则该状态将会一直存在;

    	譬如示例代码 13.2.1 中,调用 select()函数监测鼠标和键盘这两个文件描述符;
    	当 select()返回时,通过 FD_ISSET()宏判断文件描述符上是否可执行 I/O 操作;
    	如果可以执行 I/O 操作时,应在应用程序中对该文件描述符执行 I/O 操作,以清除文件描述符的就绪态;
    	如果不清除就绪态,那么该状态将会一直存在,那么下一次调用 select()时,文件描述符已经处于就绪态了,将直接返回。
    

    同理对于 poll()函数来说亦是如此,譬如示例代码 13.2.3,当 poll()成功返回时,检查文件描述符是否称为就绪态,如果文件描述符上可执行 I/O 操作时,也需要对文件描述符执行 I/O 操作,以清除就绪状态。


mmap()

定义:用于内存映射的系统调用函数

通常用于将文件或设备映射到进程的地址空间,以便对其进行读取和写入操作。

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr:指定映射的起始地址,通常传入NULL表示由系统自动分配。
  • length:指定映射的长度,以字节为单位。
  • prot:指定内存映射区域的保护方式,比如可读、可写、可执行等。
  • flags:指定映射区域的属性,比如映射文件、映射匿名内存等。
  • fd:指定要映射的文件描述符,如果映射匿名内存则传入-1。
  • offset:指定文件映射的偏移量。

mmap()函数成功时返回映射区域的起始地址,失败时返回MAP_FAILED。

munmap()

用于解除指定内存映射区域的映射关系释放内核为该映射区域所分配的资源

int munmap(void *addr, size_t length);
  • addr:指定要解除映射的起始地址。
  • length:指定要解除映射的长度,通常与mmap()时传入的长度一致。

munmap()函数成功时返回0,失败时返回-1。

示例用法

以下是一个简单的示例,展示了如何使用mmap()函数将一个文件映射到内存中,并使用munmap()函数解除映射关系:

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main() {
    int fd;
    char *file_data;
    off_t len;

    // 打开文件
    fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 获取文件大小
    len = lseek(fd, 0, SEEK_END);

    // 映射文件到内存
    file_data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
    if (file_data == MAP_FAILED) {
        perror("mmap");
        return 1;
    }

    // 使用映射的文件数据做一些操作...

    // 解除映射关系
    if (munmap(file_data, len) == -1) {
        perror("munmap");
        return 1;
    }

    // 关闭文件
    close(fd);

    return 0;
}

上述示例中,首先打开一个文件,然后使用mmap()函数将文件映射到内存中,并最终使用munmap()函数解除映射关系。在实际应用中,需要注意内存映射的参数设置和错误处理,以确保操作的正确性和稳定性。


ioctl()

ioctl函数的全称是"input/output control",是一个系统调用函数;

通过ioctl函数,用户可以向设备发送特定的命令(ioctl命令),以实现对设备的配置、控制和查询等操作。

原型

int ioctl(int fd, unsigned long request, ...);
  • fd:设备文件描述符或者套接字描述符。
  • request:ioctl命令,用于指定具体的操作。
  • ...:可选参数,用于传递ioctl命令需要的参数。

ioctl()函数成功时返回0,失败时返回-1。

使用ioctl函数的步骤

  1. 打开设备文件或者套接字,获取文件描述符。

  2. 调用ioctl函数,传入文件描述符、ioctl命令以及可能需要的参数。

  3. 常用的 request 包 括FBIOGET_VSCREENINFO、FBIOPUT_VSCREENINFO、FBIOGET_FSCREENINFO

    他们分别为获取可变参数(fb_var_screeninfo),设置可变参、获取固定参(struct fb_fix_screeninfo)

    若第二个参数是FBIOGET_VSCREENINFO或FBIOGET_FSCREENINFO:
        需提前定义一个括号内对应结构体的指针的地址作为第三个参数,函数调用成功,设备信息都在结构体内
    如果第二个参数是FBIOPUT_VSCREENINFO:
    	则没有第三个参数;
    

示例用法

以下是一个简单的示例,展示了如何使用ioctl函数向设备发送命令:

/*
首先打开设备文件`/dev/mydevice`,
然后使用`ioctl`函数向设备发送`MY_IOCTL_COMMAND`命令,并**传递一个整型参数`value`**。
通过这种方式,用户可以**根据具体的设备需求调用相应的ioctl命令**,实现对**设备的控制和配**置。

需要注意的是,**具体的ioctl命令和参数取决于设备的类型和驱动程序的实现**,
因此在使用`ioctl`函数时需要参考相应的文档或者驱动程序源码。
*/
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>

int main() {
    int fd;
    int ret;
    int value = 1;

    // 打开设备文件
    fd = open("/dev/mydevice", O_RDWR);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 发送ioctl命令
    ret = ioctl(fd, MY_IOCTL_COMMAND, &value);
    if (ret == -1) {
        perror("ioctl");
        return 1;
    }

    // 关闭设备文件
    close(fd);

    return 0;
}

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

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

相关文章

kylin-麒麟操作系统-安装内存泄露补丁-以及kylin-kms-activation.service服务不断重启解决思路

文章目录 前言1. 问题现象1.1 使用journalctl命令查看更详细的日志信息 2. 解决思路2.1 思路一&#xff1a;2.2 思路二&#xff1a;2.3 合理的解法: 3. 扩展-修复内存泄露3.1 查看自己使用的镜像3.2 到麒麟官网下载相应的补丁包3.3 安装步骤3.4 重启kylin-kms-activation.servi…

python如何另起一行

python 字符串换行的三种方式&#xff1a; 第一种&#xff1a;三个单引号 print 我是一个程序员 我刚开始学习python 第二种&#xff1a;三个双引号 print """ 我是一个程序员 我刚开始学习python""" 第三种&#xff1a;\结尾 print "我是…

生成式AI,搜索赛道的又一个黄金十年

文&#xff5c;白 鸽 编&#xff5c;王一粟 随着生成式AI的发展&#xff0c;搜索引擎正在被重构&#xff0c;越来越多玩家开始布局AI搜索赛道。 一方面&#xff0c;传统搜索引擎/浏览器正借助AI技术的重构重新焕发生机&#xff0c;无论是移动端还是PC端&#xff0c;都在抢占…

GHA高质量原创文章是什么?

GHA文章是一种专为提高搜索引擎优化&#xff08;SEO&#xff09;效果而设计的高质量原创内容。GHA代表高质量&#xff0c;这些文章通过精心编写和策略布局&#xff0c;就是为了帮助网站迅速在Google等搜索引擎上获得排名&#xff0c;写一篇能在Google上获得高排名的文章&#x…

postman注入csrf

示例脚本 参数配置位置 必要参数 django项目仅需要设置domain即可&#xff0c;比如www.baidu.com,baidu.com尽量域名精确避免修改到其他域的参数 必须把这个domain添加到 cookies->Manage cookies ->Domains Allowlist 中&#xff0c;否则cookie的注入失败 代码 // 必…

P1516 青蛙的约会(exgcd)

一些前置知识&#xff1a; 1.扩展欧几里得算法&#xff1a; axbygcd(a,b) 方程一个可行的解&#xff08;x1,y1&#xff09;求法&#xff1a; int exgcd(int a,int b,int &x,int &y) {if(!b){x1,y0; return a;}int dexgcd(b,a%b,y,x);y-a/b*x;return d; }2.由axbygcd…

URP简洁的instance的写法

材质还是要开启enable instance&#xff0c;这是上一次的写法 https://dbbh666.blog.csdn.net/article/details/136644181 最近发现更适合我个人的习惯的写法 就是代码控制这个整个过程 C#代码是这样的&#xff0c;获取一个mesh&#xff0c;获取每个mesh的transform&#xff0c…

UE5 摄像机图像采集到材质 映射到 UI 和 物体表面

一.创建SceneCapture2D的组件 二.创建用于 映射的 贴图 三.将RenderTarget贴图放到SceneCapture2D的摄像机上Scene Capture的TextureTarget 四.这个时候的映射贴图&#xff0c;产生的材质可以直接。放到Plane上。 五&#xff0c;但是如果要用于UI,还需要更改SceneCapture2D的摄…

基于SpringBoot的在线答疑系统

你好呀&#xff0c;我是计算机专业毕业生&#xff0c;专注于在线教育平台的开发与实现。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术 Spring Boot框架 工具&#xff1a;IntelliJ IDEA、Navicat、Maven、Tomcat 系统展示 首页 个人中心…

【Python】简单的数据类型——int、float、bool、str

目录 1. 整数类型 int 2. 浮点数类型 float 3. 布尔类型 bool 4. 字符串 str 5. 格式化输出 6. 类型转换 6.1 隐式类型转换 6.2 显示类型转换 7. 标准输入 1. 整数类型 int a 10 print(type(a)) print(type(-2))<class int> <class int>测试整型能表示的…

docker私有云仓库Harbor部署及使用

文章目录 一、前置准备1、安装docker、docker-compose 二、安装harbor1、下载Harbor2、证书3、配置文件4、安装5、docker使用6、k8s使用&#xff08;1.28版本containerd&#xff09; 三、常用运维1、重启 一、前置准备 1、安装docker、docker-compose centos7安装与卸载docke…

2024年【道路运输企业安全生产管理人员】考试题库及道路运输企业安全生产管理人员考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年道路运输企业安全生产管理人员考试题库为正在备考道路运输企业安全生产管理人员操作证的学员准备的理论考试专题&#xff0c;每个月更新的道路运输企业安全生产管理人员考试试题祝您顺利通过道路运输企业安全生…

牛客NC313 两个数组的交集 C++

牛客NC313 两个数组的交集 C 思路&#x1f914;&#xff1a; 用哈希表存储第一个数组&#xff0c;再和第二个数组对比&#xff0c;对比成功就添加到新的数组中&#xff0c;之后将哈希表的该位置变为false&#xff0c;防止重复添加。这里数据范围仅有1000&#xff0c;所以我们可…

Windows10系统中安装Maven 3.8.8的步骤

Windows10系统中安装Maven 3.8.8的步骤 1、前提 因已安装好了JDK17,需要安装跟JDK17对应的版本,选了maven3.8.8 2. 下载 Maven 访问 Apache Maven 官网下载页面。选择下载:apache-maven-3.8.8-bin.zip 3、解压缩 4、增加系统环境变量 MAVEN_HOME =C:\hmf\apache-maven…

cppbase阶段汇总

第一章 C与C 本章主要讲解C相较于C一些独有的比较重要的知识点。 C源文件后缀名&#xff1a;.cc或.cpp 头文件后缀名&#xff1a;.hh或.hpp 安装g命令&#xff1a;sudo apt install g 编译命令&#xff1a;g filename.cc [-o name] 首先从C的 hello,world 程序入手&#xff0c…

【C++笔记】类和对象的深入理解(一)

【C笔记】类和对象的深入理解(一) &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】类和对象的深入理解(一)前言一.类的定义1.1类定义格式1.2访问限定符1.3类域 二.实例化2.1 实例化概念2.2对象大小 三.this指针四.练…

8月29日wpf

小语 折磨我们的往往是想象&#xff0c;而不是真实。 学wpf 7.07 1.vs如何创建新项目&#xff1f; 退出&#xff0c;创建新项目&#xff0c;点c#&#xff0c;windows&#xff0c;进入界面 2.app.config在哪里&#xff1f; 好像只有这个。。。 试一下&#xff0c;不是 我…

CSS基础 什么是盒模型

是什么 当对一个文档进行布局&#xff08;layout&#xff09;的时候&#xff0c;浏览器的渲染引擎会根据标准之一的 CSS 基础框盒模型&#xff08;CSS basic box model&#xff09;&#xff0c;将所有元素表示为一个个矩形的盒&#xff08;box&#xff09; 一个盒子由四个部分…

【YOLO系列】YOLO算法改进史

目录 前言YOLOv1YOLOv2YOLOv3YOLOv4YOLOv5YOLOv6YOLOv7YOLOv8YOLOv9YOLOv10对比待更新 前言 YOLO&#xff08;You Only Look Once&#xff09;是一种革命性的目标检测算法&#xff0c;以其快速和高效的性能而闻名。自2015年YOLOv1的首次推出以来&#xff0c;YOLO系列已经经历了…

Kali的相关学习、永恒之蓝漏洞(MS17-010)、ms12-020漏洞(蓝屏攻击)

学习任务 熟悉kali网络配置&#xff0c;nat模式和桥接模式 熟悉nmap使用 熟悉msfconsole使用 熟练掌握如何利用ms17-010&#xff0c;ms08_067 kali网络配置 资料&#xff1a;07-网络安全-kail linux 网络配置&#xff08;基础篇&#xff09; - Jaoany - 博客园 (cnblogs.…