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,一经查实,立即删除!

相关文章

区块链签名种类

1. eth_sign 简介&#xff1a;最早实现的签名方法&#xff0c;用于对任意数据进行签名。签名内容&#xff1a;直接对原始消息的哈希值进行签名。特点&#xff1a; 安全性较低&#xff0c;因为签名的消息没有明确的上下文或结构。很容易被滥用&#xff0c;攻击者可以伪造签名内…

AI-安全-B站

1 需求 百度-林道正-《大模型合规探索》火山引擎-林泽韬-《大模型安全挑战与防护实践》Chamd5-bayuncao-《基于RAG的AI代码审计框架》德国电信咨询有限公司-杨麟-《AI在SOC中的应用发展》360-李亚青-《以模制模&#xff0c;大模型安全的解决之道》金晴云华-富吉祥-《安全大脑在…

基于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…

TDengine 新功能 复合主键

1. 简介 从 TDengine 3.3.0.0 版本之后&#xff0c;新增了复合主键的功能。 TDengine 原来的时间列是不允许有重复时间戳的&#xff0c;有了复合主键功能后&#xff0c;时间列即允许有重复&#xff0c;重复后的时间戳按紧跟其后第二列主键列的值来确定唯一性。 此功能的常用…

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通信的基本概念、使用方…

M9484C VXG 矢量信号发生器- 110GHz-

M9484C VXG 矢量信号发生器 - 110GHz- M9484C VXG 是一款矢量信号发生器&#xff0c;在每个通道上提供 2.5 GHz 调制带宽&#xff0c;能够生成高达 54 GHz 的信号。 这款 VXG 矢量信号发生器可以组成经过校准和同步的全方位综合解决方案&#xff0c;帮助您更快测试下一代无线…

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

个人总结&#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…

阿里云PolarDB 如何进行数据恢复,文档总结

PolarDB不同场景下的恢复方式文档介绍&#xff1a; PolarDB在不同误操作场景下如何恢复数据_云原生数据库 PolarDB(PolarDB)-阿里云帮助中心 1. 不管误删的是表还是数据库&#xff0c;通过快照或者pitr的方式恢复到一个新的集群 全量恢复1 - 从备份集恢复&#xff1a; 如何从…

C#请求https提示未能为 SSL/TLS 安全通道建立信任关系

System.Net.WebException: 基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系 &#xff0c;这个错误通常表明你的应用程序在尝试建立一个安全的 SSL/TLS 连接时遇到了问题。这通常是由于证书验证失败引起的。证书验证失败可能有几个原因&#xff1a; 证书不受信任&#…

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】openssl version mismatch. built against 30000010, you have 30200020

错误&#xff1a;openssl version mismatch. built against 30000010, you have 30200020 这个错误通常是因为系统中安装了不同版本的 OpenSSL 库&#xff0c;导致程序在编译时使用了一个版本的 OpenSSL&#xff0c;而运行时却加载了另一个版本的库。根据错误信息&#xff0c;您…