UNIXC01 DAY03 错误处理 、动态加载02和辅助工具、内存管理与进程映射

本文探讨了多种错误处理机制,包括返回非法值、空指针及-1表示失败的方法,解析了errno与strerror在错误信息反馈中的作用,同时深入讲解了内存映射的建立与解除过程。

1 返回非法值表示失败

1.1 问题

如果一个函数的返回值存在确定的合法值域,那么就可以通过返回合法值域以外的值表示函数执行失败。

1.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:返回非法值表示失败

代码如下所示:

long fsize (const char* path)
{
	FILE* fp = fopen(path,”r”);
	if(!fp)
		return -13;
	fseek(fp,0,SEEK_END);
	long size = ftell(fp);
	fclose(fp);
	return size;   
}

上述代码中,以下代码:

if(!fp)
   return -13;

如果文件打开失败,则返回一个负数,因为合理的文件字节数不可能为负,负数在合理的数域之外表示失败。

1.3 完整代码

本案例的完整代码如下所示:

long fsize (const char* path) 
{
	FILE* fp = fopen(path,”r”);
	if(!fp)
		return -13;
	fseek(fp,0,SEEK_END);
	long size = ftell(fp);
	fclose(fp);
	return size;
}

2 返回空指针表示失败

2.1 问题

如果一个函数的返回值是一个指针,那么就可以通过返回空指针(即值为0的指针,通常用NULL宏表示)表示函数执行失败。

2.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:返回空指针表示失败

代码如下所示:

const char* strmax (const char* a, const char* b) 
{
    return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;
}

上述代码中,以下代码:

    return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;

a、b中有一个为假时,返回NULL,表示无法比较两个字符串。

2.3 完整代码

本案例的完整代码如下所示:

const char* strmax (const char* a, const char* b) 
{
    return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;
}

3 返回-1表示失败

3.1 问题

返回 0 表示成功,返回 -1 表示失败,不输出数据或通过指针型参数输出数据。

3.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:返回-1表示失败

代码如下所示:

int mod (int a, int b, int* c) 
{
    if (b == 0)
        return -1;
    *c = a % b;
    return 0; 
}

上述代码中,以下代码:

     if (b == 0)
        return -1;

因为ab求余数,余数可以是负数、零、正数,此时返回几都是合理范围内的值。此时就需要使用指针型参数c输出数据,而用 0 表示成功,返回 -1 表示失败。

3.3 完整代码

本案例的完整代码如下所示:

int mod (int a, int b, int* c) 
{
    if (b == 0)
        return -1;
    *c = a % b;
    return 0; 
}

4 错误号和错误信息

4.1 问题

系统预定义的整型全局变量errno中存储了最近一次系统调用的错误编号。该整数形式的错误号可以被转换为有意义的字符串。

4.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:错误号和错误信息

代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
    char* p = (char*)malloc (-1);
    if (! p)
    {
    	fprintf (stderr, "malloc: %s\n", strerror (errno));
		exit (EXIT_FAILURE);
    }
    scanf("%s", p);
    printf("%s", p);
}

上述代码中,以下代码:

    if (! p)
    {
        fprintf (stderr, "malloc: %s\n", strerror (errno));
        exit (EXIT_FAILURE);
    }

当申请内存失败后,系统预定义的整型全局变量errno中存储了错误编号。

注意:该编号必须包含errno.h头函数。

使用strerror函数可以将上述错误编号转为字符串。

注意:该函数必须包含string.h头函数。

4.3 完整代码

本案例中的完整代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
    char* p = (char*)malloc (-1);
    if (! p)
    {
        fprintf (stderr, "malloc: %s\n", strerror (errno));
        exit (EXIT_FAILURE);
    }
    scanf("%s", p);
    printf("%s", p);
}

5 不能根据错误号判断是否出错

5.1 问题

虽然所有的错误号都不是零,但是因为在函数执行成功的情况下错误号全局变量**errno**不会被修改,所以不能用该变量的值为零或非零,做为出错或没出错的判断依据。

5.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:错误做法

代码如下所示:

char* p = (char*)malloc (0xffffffff);
FILE* fp = fopen ("/etc/passwd", "r");
if (errno)
    fprintf (stderr, "无法打开口令文件!\n");

上述代码中,以下代码:

if (errno)

不能直接使用错误号判断是否出错。

步骤二:正确做法

代码如下所示:

    FILE* fp = fopen ("/etc/passwd", "r");
    if(! fp)
        fprintf (stderr, "无法打开口令文件:%s\n", strerror (errno));

上述代码中,以下代码:

    if(! fp)

先根据函数的返回值判断是否出错,在确定出错的前提下再根据errno的值判断具体出了什么错。

5.3 完整代码

本案例中的完整代码如下所示:

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
	/**********错误做法**************
    char* p = (char*)malloc (0xffffffff);
    FILE* fp = fopen ("/etc/passwd", "r");
    if (errno)
        fprintf (stderr, "无法打开口令文件!\n");
	***********正确做法*************/
    FILE* fp = fopen ("/etc/passwd", "r");
    if(! fp)
        fprintf (stderr, "无法打开口令文件:%s\n", strerror (errno));
    fclose(fp);
}

6 内存映射的建立与解除

6.1 问题

所谓内存分配与释放,其本质就是建立或解除从虚拟内存到物理内存的映射,并在底层维护不同形式的数据结构,以把虚拟内存的占用与空闲情况记录下来。

6.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:建立内存映射

代码如下所示:

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
    if (p == MAP_FAILED)
    {
        perror ("mmap");
        exit (EXIT_FAILURE);
    }
    strcpy (p, "Hello, Memory !");
    printf ("%s\n", p);
    
    return 0;
}

上述代码中,以下代码:

    char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
    if (p == MAP_FAILED)
    {
        perror ("mmap");
        exit (EXIT_FAILURE);
    }

使用mmap函数建立虚拟内存到物理内存或文件的映射。下面为函数形参的说明:
第一个形参为映射区内存起始地址,NULL系统自动选定后返回。
第二个形参为映射区字节长度,自动按页 (4K) 圆整。
第三个形参为映射区访问权限,可取以下值
PROT_READ - 映射区可读
PROT_WRITE - 映射区可写
PROT_EXEC - 映射区可执行
PROT_NONE - 映射区不可访问
第四个形参为映射标志,可取以下值
MAP_ANONYMOUS - 匿名映射,将虚拟内存映射到物理内存而非文件,忽略fd和offset参数
MAP_PRIVATE - 对映射区的写操作只反映到缓冲区中,并不会真正写入文件
MAP_SHARED - 对映射区的写操作直接反映到文件中
MAP_DENYWRITE - 拒绝其它对文件的写操作
MAP_FIXED - 若在 start上无法创建映射,则失败(无此标志系统会自动调整)
MAP_LOCKED - 锁定映射区,保证其不被换出
第五个参数为文件描述符。
第六个参数为文件偏移量,自动按页 (4K) 对齐。

步骤二:解除内存映射

代码如下所示:

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
    if (p == MAP_FAILED)
    {
        perror ("mmap");
        exit (EXIT_FAILURE);
    }
    strcpy (p, "Hello, Memory !");
    printf ("%s\n", p);
    
    if (munmap (p, 4096) == -1) 
    {
        perror ("munmap");
        exit (EXIT_FAILURE);
    }
    strcpy (p += 4096, "Hello, Memory !");
    printf ("%s\n", p);
    if (munmap (p, 4096) == -1)
    {
        perror ("munmap");
        exit (EXIT_FAILURE);
    }
    return 0;
}

上述代码中,以下代码:

    if (munmap (p, 4096) == -1) 
    {
        perror ("munmap");
        exit (EXIT_FAILURE);
    }

使用munmap函数解除虚拟内存到物理内存或文件的映射。该函数的第一个形参为映射区内存起始地址,必须是页的首地址,第二个形参为映射区字节长度,自动按页 (4K) 圆整。munmap函数允许对映射区的一部分解映射,但必须按页。

6.3 完整代码

本案例的完整代码如下所示:

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
    if (p == MAP_FAILED)
    {
        perror ("mmap");
        exit (EXIT_FAILURE);
    }
    strcpy (p, "Hello, Memory !");
    printf ("%s\n", p);
    
    if (munmap (p, 4096) == -1) 
    {
        perror ("munmap");
        exit (EXIT_FAILURE);
    }
    strcpy (p += 4096, "Hello, Memory !");
    printf ("%s\n", p);
    if (munmap (p, 4096) == -1)
    {
        perror ("munmap");
        exit (EXIT_FAILURE);
    }
    return 0;
}
标题基于Python的汽车之家网站舆情分析系统研究AI更换标题第1章引言阐述汽车之家网站舆情分析的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景意义说明汽车之家网站舆情分析对汽车行业及消费者的重要性。1.2国内外研究现状概述国内外在汽车舆情分析领域的研究进展成果。1.3论文方法及创新点介绍本文采用的研究方法及相较于前人的创新之处。第2章相关理论总结评述舆情分析、Python编程及网络爬虫相关理论。2.1舆情分析理论阐述舆情分析的基本概念、流程及关键技术。2.2Python编程基础介绍Python语言特点及其在数据分析中的应用。2.3网络爬虫技术说明网络爬虫的原理及在舆情数据收集中的应用。第3章系统设计详细描述基于Python的汽车之家网站舆情分析系统的设计方案。3.1系统架构设计给出系统的整体架构,包括数据收集、处理、分析及展示模块。3.2数据收集模块设计介绍如何利用网络爬虫技术收集汽车之家网站的舆情数据。3.3数据处理分析模块设计阐述数据处理流程及舆情分析算法的选择实现。第4章系统实现测试介绍系统的实现过程及测试方法,确保系统稳定可靠。4.1系统实现环境列出系统实现所需的软件、硬件环境及开发工具。4.2系统实现过程详细描述系统各模块的实现步骤及代码实现细节。4.3系统测试方法介绍系统测试的方法、测试用例及测试结果分析。第5章研究结果分析呈现系统运行结果,分析舆情数据,提出见解。5.1舆情数据可视化展示通过图表等形式展示舆情数据的分布、趋势等特征。5.2舆情分析结果解读对舆情分析结果进行解读,提出对汽车行业的见解。5.3对比方法分析将本系统其他舆情分析系统进行对比,分析优劣。第6章结论展望总结研究成果,提出未来研究方向。6.1研究结论概括本文的主要研究成果及对汽车之家网站舆情分析的贡献。6.2展望指出系统存在的不足及未来改进方向,展望舆情
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值