Java 转 C之错误处理

提纲:

  1. 从 Java 转向 C 的错误处理概念概述
  2. Java 异常机制与 C 返回值/errno 的对比
  3. C 中错误处理的常用方式详解
    • 函数返回值
    • errno 全局错误码
    • 自定义错误码
    • setjmp/longjmp 模拟异常
  4. 常见错误码列表(POSIX 环境为例)
  5. Java 与 C 的错误处理示例对比
  6. 全量示例:从文件读数据并处理错误
  7. 最佳实践与总结

从 Java 转向 C 的错误处理概念概述

在 Java 中,错误处理通过异常(Exception)机制实现:当发生错误时,抛出一个异常对象,并在 try/catch 块中捕获该异常,从而中断当前执行流并转入相应的错误处理逻辑。

在 C 中,没有内置的异常机制。C 程序员通常通过检查函数返回值来判断调用是否成功,再依据 errno(全局错误码变量)获取错误原因。此外,也可自行定义返回码、使用条件判断处理逻辑,或在极少数情况下用 setjmp()longjmp() 模拟类似异常的跳转行为。C 的这种方式更显底层,需要手动检查和处理每个错误分支。


Java 异常机制与 C 返回值/errno 的对比

特性Java(异常)C(返回值/errno)
错误处理方式try/catch 捕获异常对象检查函数返回值(如NULL或-1)加上 errno 分析
错误信息获取异常对象具详细信息 (e.getMessage())errno 搭配 strerror(errno) 获取简要信息
流程控制异常可将执行流转入 catch / finally通过 if 判断返回值决定后续流程
资源清理finally 块自动实现资源清理需手动在每个错误分支中显式释放资源
类型区分有受检和非受检异常无异常类型,错误码与逻辑由程序员自定义

简而言之,Java 异常让错误处理更高层次、更清晰,而 C 的返回值+errno 方式则更底层、更灵活,但需要更多代码来保持清晰性和安全性。


C 中错误处理的常用方式详解

  1. 函数返回值
    许多标准库函数在错误时返回特定值。例如:

    • fopen() 文件打开失败返回 NULL
    • 某些系统调用(在 POSIX 下)失败返回 -1

    通过检查返回值是否为预期的成功值来判断调用是否成功。

    示例

    FILE *fp = fopen("nonexist.txt", "r");
    if (fp == NULL) {// 出错处理
    }
    
  2. errno 全局错误码
    errno 是一个全局变量,函数调用失败时常会设置 errno
    使用 #include <errno.h> 引入,strerror(errno) 可将 errno 转为可读字符串。

    示例

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>int main() {FILE *fp = fopen("nonexist.txt", "r");if (fp == NULL) {fprintf(stderr, "Error: %s\n", strerror(errno));return EXIT_FAILURE;}fclose(fp);return EXIT_SUCCESS;
    }
    
  3. 自定义错误码
    自己编写的函数可定义返回码,例如 0 表示成功,非0表示不同错误类型。调用者用 ifswitch 来判断和处理。

    示例

    #define ERR_OK 0
    #define ERR_FILE_NOT_FOUND 1
    #define ERR_MEMORY 2int read_file(const char *filename) {FILE *fp = fopen(filename, "r");if (!fp) return ERR_FILE_NOT_FOUND;char *buf = malloc(100);if (!buf) {fclose(fp);return ERR_MEMORY;}// ...处理...free(buf);fclose(fp);return ERR_OK;
    }
    
  4. setjmp/longjmp 模拟异常
    setjmp()longjmp() 提供非本地跳转,能在错误时跳回到预先设置的点,类似异常的非正常返回。不过这种方式不如 Java 异常优雅,不建议过度使用。

    示例

    #include <stdio.h>
    #include <setjmp.h>jmp_buf buf;void error_occured() {longjmp(buf, 1);
    }int main() {if (setjmp(buf)) {printf("An error occurred!\n");} else {error_occured(); printf("No error.\n"); // 不会执行}return 0;
    }
    

常见错误码列表(POSIX 环境为例)

C 标准本身未定义详细错误码列表,以下错误码是 POSIX 系统常见的示例:

错误码含义(通俗解释)示例场景
EACCES没有权限访问资源打开无读权限文件时 fopen() 失败
ENOENT文件或目录不存在fopen("nonexist.txt", "r") 失败
ENOMEM内存不足malloc() 返回 NULL 并 errno=ENOMEM
EIOI/O 底层错误磁盘故障读取时出错
EMFILE打开的文件过多同时打开过多文件,fopen() 失败
ENOSPC磁盘空间不足fwrite() 时磁盘已满
EINVAL无效参数fseek() 使用无效参数
EPERM操作不允许无权限的系统操作
EPIPE管道破裂向无读端管道写数据

说明

  • 不同系统的错误码可能有差异。
  • 使用前请查阅平台文档,确保了解对应错误码的含义。

Java 与 C 的错误处理示例对比

Java 示例(异常)

public static void main(String[] args) {try {readFile("nonexist.txt");} catch (FileNotFoundException e) {System.err.println("File not found: " + e.getMessage());} catch (IOException e) {System.err.println("IO error: " + e.getMessage());}
}static void readFile(String filename) throws IOException {BufferedReader br = new BufferedReader(new FileReader(filename));String line = br.readLine();br.close();System.out.println("First line: " + line);
}

C 示例(返回值+errno)

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>int main() {FILE *fp = fopen("nonexist.txt", "r");if (!fp) {fprintf(stderr, "Error: %s\n", strerror(errno));return EXIT_FAILURE;}// 使用fpfclose(fp);return EXIT_SUCCESS;
}

对比可知,Java中错误会自动转入 catch 块处理,C中需手动检查返回值并使用 errno


全量示例:从文件读数据并处理错误

以下C示例展示如何处理多种错误情况(文件不存在、没有数据、I/O错误),并给出自定义错误码。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>#define ERR_OK 0
#define ERR_FILE_OPEN 1
#define ERR_NO_DATA 2
#define ERR_IO 3int compute_average(const char *filename, double *avg) {FILE *fp = fopen(filename, "r");if (!fp) {return ERR_FILE_OPEN;}int sum = 0;int count = 0;int val;while (fscanf(fp, "%d", &val) == 1) {sum += val;count++;}if (ferror(fp)) {fclose(fp);return ERR_IO;}fclose(fp);if (count == 0) {return ERR_NO_DATA;}*avg = (double)sum / count;return ERR_OK;
}int main() {double average;int status = compute_average("numbers.txt", &average);if (status == ERR_OK) {printf("Average: %.2f\n", average);} else {if (status == ERR_FILE_OPEN) {fprintf(stderr, "Error opening file: %s\n", strerror(errno));} else if (status == ERR_IO) {fprintf(stderr, "I/O error occurred: %s\n", strerror(errno));} else if (status == ERR_NO_DATA) {fprintf(stderr, "No data found in file.\n");} else {fprintf(stderr, "Unknown error.\n");}}return 0;
}

最佳实践与总结

  • 检查返回值:每次调用标准库函数(如 fopen(), malloc())后,立即检查返回值判断成功或失败。
  • 使用 errno:在函数失败后检查 errno 并用 strerror(errno) 打印错误原因。
  • 定义统一错误码:对自定义函数返回值进行统一定义(如 ERR_OKERR_NO_DATA),便于调用方处理。
  • 资源释放:在出错路径上显式释放已分配内存或已打开的文件,防止资源泄露。
  • 工具检测:借助 gdbvalgrind 等工具调试和检查内存错误、泄漏问题。
  • 模块化与文档化:在头文件中注明函数可能的错误返回值及其含义,让调用者快速理解处理逻辑。

总之,从 Java 转向 C 后,错误处理的重任更多落在开发者身上,需要小心谨慎和良好编码习惯,以确保程序的稳定性和可维护性。

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

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

相关文章

基于BiLSTM-CRF的中文电子病历命名实体识别

声明&#xff1a;博客未经允许禁止抄袭转载。 前言 最近有粉丝在后台私信我能不能更一篇关于命名实体识别(NER&#xff0c;Named Entity Recognition)的经典模型BiLSTM-CRF的实战文章&#xff0c;前段时间有点忙所有一直没有更新&#xff0c;趁着最近有点空&#xff0c;满足一…

k8s 优雅监控jvm及dump heap的方案探讨

背景 k8s cluster 的健康检测失败会主动重启pod&#xff0c;而大部份情况下健康检测失败都是由full gc引起的。往往发生重启时已经没有条件dump heap排查full gc的原因。 如何监控 为了避免因健康检测失败而导致的pod重启&#xff0c;我们需要实施有效的监控策略&#xff0c;这…

TPM 2.0:安全固件的新标准

得益于可信计算组 ( TCG ) 推出的全新 TPM 2.0规范&#xff0c;联网设备可以更好地抵御网络攻击&#xff0c;并且不太可能受到错误的攻击。 制造商将可信平台模块 (TPM) 附加到设备上&#xff0c;以帮助用户和管理员验证其身份、生成和存储加密密钥以及确保平台完整性。 在 T…

ensp实验-vrrp多网关配置

一、交换机与路由的配置区别 1. 角色定义交换机&#xff1a; Master 或 Backup: 交换机通常作为 Master 或 Backup 设备参与 VRRP&#xff0c;负责在主设备故障时接替其工作。路由器&#xff1a; Master 或 Backup: 路由器同样可以作为 Master 或 Backup 设备…

黑盒测试方法

‌黑盒测试是一种软件测试方法&#xff0c;它通过向系统提供输入并检查输出结果来验证系统的功能是否符合需求。‌黑盒测试主要关注软件的功能性&#xff0c;而不是其内部结构或工作原理。以下是几种常见的黑盒测试顺序方法&#xff1a; 场景设计法‌&#xff1a; 通过模拟实际…

游戏引擎学习第38天

仓库: https://gitee.com/mrxiao_com/2d_game 回顾上次的内容。 我们之前讨论了将精灵放在屏幕上&#xff0c;但颜色错误的问题。问题最终查明是因为使用了一个调整工具&#xff0c;导致文件的字节顺序发生了变化。重新运行“image magic”工具对一些大图像进行重新处理后&am…

aws(学习笔记第十六课) 使用负载均衡器(ELB)解耦webserver以及输出ELB的日志到S3

aws(学习笔记第十六课) 使用负载均衡器(ELB)以及输出ELB的日志到S3 学习内容&#xff1a; 使用负载均衡器(ELB)解耦web server输出ELB的日志到S3 1. 使用负载均衡器(ELB) 全体架构 使用ELB(Elastic Load Balancer)能够解耦外部internet访问和web server之间的耦合&#xff0c…

深入理解C#的TCPIP通信机制

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;在分布式系统和实时数据交换应用中&#xff0c;C#作为一种现代面向对象编程语言&#xff0c;利用其***命名空间下的Socket类&#xff0c;提供强大的TCP/IP通信功能。本文将探讨C#中TCP/IP通信的基本概念、使用方…

高项 - 项目管理原则与项目绩效域

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 博文更新参考时间点&#xff1a;2024-12 高项 - 章节与知识点汇总&#xff1a;点击跳转 文章目录 高项 - 项目管理原则与项目绩效域项目管理12条原则原则1&#xff1a;成为勤勉、尊重和关心他人的管家 (p202)原则…

仿真技术助力高尔夫球打破传统设计局限,实现球杆强大的功能

Altair近日宣布与业内领先的高尔夫装备制造商 Cleveland Golf 开展合作&#xff0c;以设计新款 HiBore XL 球杆。借助 Altair 先进的仿真与设计技术&#xff0c;Cleveland Golf 不断刷新高尔夫装备的行业标准&#xff0c;并在球杆产品设计方面实现突破。 Cleveland Golf 借助 A…

python字符串处理基础操作总结

1.去掉空格或者特殊符号 input_str.strip() #去掉所有空格 input_str.lstrip() #去掉左边空格 input_str.rstrip() #去掉右边空格 def print_hi():input_str 今天天气不错&#xff0c;风和日丽 out input_str.strip()print(input_str)print(out)if __name__ __main__:print…

Trimble X9三维激光扫描仪高效应对化工厂复杂管道扫描测绘挑战【沪敖3D】

化工安全关系到国计民生&#xff0c;近年来随着化工厂数字化改革不断推进&#xff0c;数字工厂逐步成为工厂安全管理的重要手段。而化工管道作为工厂设施的重要组成部分&#xff0c;由于其数量多、种类繁杂&#xff0c;一直是企业管理的重点和难点。 传统的化工管廊往往缺乏详…

日志基础示例python和c++

文章目录 0. 引言1. python2. c 0. 引言 本文主要记录python版本和c版本常用的日志基础示例。 1. python python版本常用的是logging库&#xff0c;结合colorlog库&#xff0c;可根据不同日志级别打印不同颜色的日志&#xff0c;为了便于分析问题&#xff0c;还添加了日志保…

【Linux】基础IO-----文件详解

目录 一、文件理解&#xff1a; 二、C语言的文件操作&#xff1a; 1、fopen&#xff1a; 什么是当前路径&#xff1a; 2、fclose&#xff1a; 3、fwrite&#xff1a; 4、默认打开的三个流&#xff1a; 三、系统文件&#xff1a; 1、open&#xff1a; 2、close&#xf…

第7章:响应式设计 --[CSS零基础入门]

什么是响应式设计 响应式设计&#xff08;Responsive Web Design, RWD&#xff09;是一种网页设计和开发的方法&#xff0c;它使网站能够根据用户的设备特性&#xff08;如屏幕尺寸、分辨率、方向等&#xff09;自动调整其布局和内容。响应式设计的目标是确保网站在不同类型的…

探索 ONLYOFFICE 8.2 版本:更高效、更安全的云端办公新体验

引言 在当今这个快节奏的时代&#xff0c;信息技术的发展已经深刻改变了我们的工作方式。从传统的纸质文件到电子文档&#xff0c;再到如今的云端协作&#xff0c;每一步技术进步都代表着效率的飞跃。尤其在后疫情时代&#xff0c;远程办公成为常态&#xff0c;如何保持团队之间…

Vue-打印自定义HTML表格

自定义打印方法 1. 准备HTML结构 首先&#xff0c;构造了一个基本的HTML页面框架&#xff0c;并设置了页面的字符编码为UTF-8&#xff0c;以确保中文和其他特殊字符能正确显示。页面的标题设置为传入的 title 参数值。 let printStr "<html><head><met…

http1.0、1.1、2.0、 3.0

http1.0、1.1、2.0、 3.0 http1.1 引入长连接&#xff0c;在1.0&#xff0c;每次请求都需要建立新的TCP连接&#xff0c;处理请求完毕后立即断开。就导致处理大量图片&#xff0c;链接等资源&#xff0c;需要大量的连接与断开&#xff0c;造成资源浪费和时间延迟。而长连接允许…

跟着问题学15——GRU网络结构详解及代码实战

1 RNN的缺陷——长期依赖的问题 &#xff08;The Problem of Long-Term Dependencies&#xff09; 前面一节我们学习了RNN神经网络&#xff0c;它可以用来处理序列型的数据&#xff0c;比如一段文字&#xff0c;视频等等。RNN网络的基本单元如下图所示&#xff0c;可以将前面的…

pytest中使用conftest做测试前置和参数化

pytest中比较高阶的应用是&#xff0c;使用conftest去做测试前置工作、测试收尾工作和参数化。conftest是pytest的一个组件&#xff0c;用于配置测试环境和参数。通过conftest, 可以创建一个可复用的测试配置文件&#xff0c;以便在多个测试模块之间共享配置信息。即&#xff0…