gcc__attribute__((cleanup))解析

原创 Linux二进制 2024-11-06 08:20

引言

在 C/C++ 语言编程中,资源管理是一个十分重要的内容。确保资源在不再需要时被正确释放,可以避免内存泄漏和其他资源管理问题。GCC 提供了一个强大的扩展属性 __attribute__((cleanup(cleanup_function))),用于在变量作用域结束时自动调用一个清理函数。本文将详细介绍这一特性的原理、实际案例以及如何在项目中应用它。

工作原理

__attribute__((cleanup(cleanup_function))) 是 GCC 提供的一个扩展属性,用于在变量作用域结束时自动调用一个指定的清理函数。这个特性特别适用于需要确保资源在变量生命周期结束时被正确释放的场景,例如关闭文件描述符、释放内存等。

当变量的作用域结束时(例如函数返回、块结束或异常抛出),GCC 会自动调用指定的清理函数。清理函数接收一个指向变量的指针,因此可以修改变量的值或执行其他清理操作。

__attribute__((cleanup((cleanup_function))) 语法如下:

void cleanup_function(type *var);
type var __attribute__((cleanup(cleanup_function)));
  • type: 变量的类型。

  • var: 需要应用清理属性的变量。

  • cleanup_function: 清理函数,接受一个指向变量类型的指针作为参数。

代码演示

1. 释放动态分配的内存

常见的用例是确保动态分配的内存被正确释放,让我们通过代码演示一下。首先创建一个未释放申请的动态内存的 ufree_memory.c 文件,再创建一个通过 cleanup 函数释放了申请的动态内存的 free_memory.c 文件,并使用 valgrind 检测一下两个文件内存泄露情况。

源文件 ufree_memory.c

#include 
#include

int main() {
char *str = malloc(100 * sizeof(char));
if (str == NULL) {
perror("malloc");
return 1;
}

// 使用分配的内存
snprintf(str, 100, "Hello, World!");
printf("%s\n", str);

// 内存将在 main 函数结束时自动释放
return 0;
}

编译上面源文件,生成可执行文件并通过 valgrind 运行如下:

[root@localhost gcc_property]# gcc -g -o ufree_memory ufree_memory.c
[root@localhost gcc_property]# ls
ufree_memory ufree_memory.c

[root@localhost gcc_property]# valgrind --tool=memcheck --leak-check=full ./ufree_memory
==1430643== Memcheck, a memory error detector
==1430643== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==1430643== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==1430643== Command: ./ufree_memory
==1430643==
Hello, World!
==1430643==
==1430643== HEAP SUMMARY:
==1430643== in use at exit: 100 bytes in 1 blocks
==1430643== total heap usage: 2 allocs, 1 frees, 1,124 bytes allocated
==1430643==
==1430643== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1430643== at 0x4C392A1: malloc (vg_replace_malloc.c:446)
==1430643== by 0x4006FB: main (ufree_memory.c:13)
==1430643==
==1430643== LEAK SUMMARY:
==1430643== definitely lost: 100 bytes in 1 blocks
==1430643== indirectly lost: 0 bytes in 0 blocks
==1430643== possibly lost: 0 bytes in 0 blocks
==1430643== still reachable: 0 bytes in 0 blocks
==1430643== suppressed: 0 bytes in 0 blocks
==1430643==
==1430643== For lists of detected and suppressed errors, rerun with: -s
==1430643== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

通过 Valgrind 的输出,我们可以得出以下结论:

  • 内存泄漏: 100 bytes in 1 blocks are definitely lost:程序中确实存在内存泄漏,100 字节的内存块在程序结束时没有被释放。 definitely lost: 100 bytes in 1 blocksValgrind 确定这 100 字节的内存是完全丢失的,即没有被释放。

  • 内存分配和释放: total heap usage2 allocs, 1 frees, 1,124 bytes allocated:程序总共进行了 2 次内存分配,1 次内存释放,总共分配了 1,124 字节的内存。 in use at exit100 bytes in 1 blocks:在程序退出时,仍有 100 字节的内存未被释放。

  • 泄漏位置: at 0x4C392A1: malloc (vg_replace_malloc.c:446):内存泄漏发生在 malloc 调用处。 by 0x4006FB: main (ufree_memory.c:13):具体的泄漏位置是在 main 函数的第 13 行,即 char *str = malloc(100 * sizeof(char)); 这一行。

根据上述结论,我们可以确定问题出在 main 函数的第 13 行,即 char *str = malloc(100 * sizeof(char)); 分配的内存没有被释放。为了修复这个问题,可以使用 __attribute__((cleanup(cleanup_function))) 属性来确保内存被自动释放。

 

拓展Valgrind 的输出,为什么会有 2 次内存分配和 1 次内存释放?

  • 2 次内存分配:第 1 次内存分配:在 main 函数中,char *str = malloc(100 * sizeof(char)); 这一行分配了 100 字节的内存。第 2 次内存分配:Valgrind 本身可能在内部进行了一些额外的内存分配。这些分配通常是为了跟踪内存使用情况和检测内存泄漏。这些内部分配不会影响你的程序逻辑,但会出现在 Valgrind 的输出中。

  • 1 次内存释放:唯一的 1 次内存释放:Valgrind 内部分配的内存在程序结束时被释放。在你的源代码中,没有任何地方显式地释放 str 指向的 100 字节内存。因此,这 100 字节的内存没有被释放,导致内存泄漏。

源文件 free_memory.c :

#include 
#include

// 清理函数,释放内存
void free_memory(char **ptr) {
if (*ptr != NULL) {
free(*ptr);
printf("Memory freed\n");
}
}

int main() {
char *str __attribute__((cleanup(free_memory))) = malloc(100 * sizeof(char));
if (str == NULL) {
perror("malloc");
return 1;
}

// 使用分配的内存
snprintf(str, 100, "Hello, World!");
printf("%s\n", str);

// 内存将在 main 函数结束时自动释放
return 0;
}

在这个例子中,free_memory 函数会在 str 变量的作用域结束时自动调用,确保分配的内存被释放。重新编译并运行 Valgrind 检测:

[root@localhost gcc_property]# gcc -g -o free_memory free_memory.c
[root@localhost gcc_property]# ls
free_memory free_memory.c ufree_memory ufree_memory.c

[root@localhost gcc_property]# valgrind --tool=memcheck --leak-check=full ./free_memory
==1431439== Memcheck, a memory error detector
==1431439== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==1431439== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==1431439== Command: ./free_memory
==1431439==
Hello, World!
Memory freed
==1431439==
==1431439== HEAP SUMMARY:
==1431439== in use at exit: 0 bytes in 0 blocks
==1431439== total heap usage: 2 allocs, 2 frees, 1,124 bytes allocated
==1431439==
==1431439== All heap blocks were freed -- no leaks are possible
==1431439==
==1431439== For lists of detected and suppressed errors, rerun with: -s
==1431439== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

通过 Valgrind 的输出,我们可以得出以下结论:

  1. 程序输出: Hello, World!:程序成功打印了字符串 "Hello, World!"。 Memory freed:程序在 main 函数结束时调用了 free_memory 函数,释放了分配的内存,并打印了 "Memory freed"

  2. HEAP SUMMARY: in use at exit: 0 bytes in 0 blocks:程序结束时,所有分配的内存都已被释放,没有内存泄漏。 total heap usage: 2 allocs, 2 frees, 1,124 bytes allocated: 2 allocs:程序进行了两次内存分配。一次是你显式调用的 malloc(100 * sizeof(char)),另一次可能是 Valgrind 内部分配的内存。 2 frees:程序进行了两次内存释放。一次是你显式调用的 free_memory 函数释放的内存,另一次可能是 Valgrind 内部分配的内存被释放。 1,124 bytes allocated:总共分配了 1,124 字节的内存,其中 100 字节是你显式分配的,其余 1,024 字节可能是 Valgrind 内部分配的。

  3. All heap blocks were freed -- no leaks are possible:这表明所有分配的内存块都已成功释放,没有内存泄漏。

  4. ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)Valgrind 没有检测到任何错误,包括内存泄漏、越界访问等。

至此,程序按预期运行,没有检测到任何错误。我们可以确认内存泄漏问题已经得到解决。

2. 关闭文件描述符

假设我们有一个函数,需要在函数退出时确保文件描述符被关闭。可以使用 __attribute__((cleanup(cleanup_function))) 来实现这一点。

源文件 close_fd.c

#include 
#include
#include

// 清理函数,关闭文件描述符
void close_fd(int *fd) {
if (*fd >= 0) {
close(*fd);
printf("File descriptor %d closed\n", *fd);
}
}

int main() {
int fd __attribute__((cleanup(close_fd))) = open("example.txt", O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}

// 读取文件内容
char buffer[100];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read < 0) {
perror("read");
return 1;
}
buffer[bytes_read] = '\0';
printf("Read: %s\n", buffer);

// 文件描述符将在 main 函数结束时自动关闭
return 0;
}

编译上面源文件,生成并运行可执行文件,

[root@localhost gcc_property]# gcc -g -o close_fd close_fd.c
[root@localhost gcc_property]# cat example.txt
This is a demo to demonstration the usage of __attribute__((cleanup(cleanup_function)))
[root@localhost gcc_property]# ./close_fd
Read: This is a demo to demonstration the usage of __attribute__((cleanup(cleanup_function)))
File descriptor 3 closed

在这个例子中,close_fd 函数会在 fd 变量的作用域结束时自动调用,确保文件描述符被关闭。

通过打印内容,我们可以知道文件描述符已经成功关闭。但是即使程序输出了 File descriptor 3 closed,也有可能存在某些特殊情况或错误导致文件描述符没有真正关闭。如果我们想进一步确认文件描述符确实被关闭,我们也可以通过 Valgrind ,其不仅可以检测内存泄漏,还可以检测文件描述符等资源的泄漏。可以使用 Valgrind 的 --track-fds=yes 选项来跟踪文件描述符的使用情况。

Valgrind 会输出文件描述符的打开和关闭情况。如果文件描述符被正确关闭,你不会看到任何未关闭的文件描述符的警告。使用 Valgrind 检测输出如下:

[root@localhost gcc_property]# valgrind --tool=memcheck --leak-check=full --track-fds=yes ./close_fd
==1436843== Memcheck, a memory error detector
==1436843== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==1436843== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==1436843== Command: ./close_fd
==1436843==
Read: This is a demo to demonstration the usage of __attribute__((cleanup(cleanup_function)))
File descriptor 3 closed
==1436843==
==1436843== FILE DESCRIPTORS: 3 open (3 std) at exit.
==1436843==
==1436843== HEAP SUMMARY:
==1436843== in use at exit: 0 bytes in 0 blocks
==1436843== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==1436843==
==1436843== All heap blocks were freed -- no leaks are possible
==1436843==
==1436843== For lists of detected and suppressed errors, rerun with: -s
==1436843== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

这段 Valgrind 的输出解析如下:

  1. 程序输出: ReadThis is a demo to demonstration the usage of attribute((cleanup(cleanup_function))):程序成功读取并打印了文件内容。 File descriptor 3 closed:程序在 main 函数结束时调用了 close_fd 函数,关闭了文件描述符 3,并打印了关闭信息。

  2. 文件描述符跟踪: FILE DESCRIPTORS: 3 open (3 std) at exit.:程序结束时,有 3 个文件描述符仍然打开,但这 3 个文件描述符都是标准输入(0)、标准输出(1)和标准错误(2)。这意味着除了这三个标准文件描述符外,没有其他文件描述符被打开而未关闭。

  3. HEAP SUMMARY: in use at exit: 0 bytes in 0 blocks:程序结束时,所有分配的内存都已被释放,没有内存泄漏。 total heap usage1 allocs, 1 frees, 1,024 bytes allocated: 1 allocs:程序进行了 1 次内存分配。 1 frees:程序进行了 1 次内存释放。 1,024 bytes allocated:总共分配了 1,024 字节的内存。

  4. 内存泄漏检查: All heap blocks were freed -- no leaks are possible:所有分配的内存块都已成功释放,没有内存泄漏。

  5. 错误总结: ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)Valgrind 没有检测到任何错误,包括内存泄漏、越界访问等。

通过这段 Valgrind 输出,我们可以得出以下结论:

  • 文件描述符管理正确:程序正确地打开了文件描述符 3 并在 main 函数结束时关闭了它。除了标准输入、标准输出和标准错误外,没有其他文件描述符被打开而未关闭。

  • 内存管理正确:程序正确地分配和释放了内存,没有内存泄漏。

  • 程序运行正常:程序按预期运行,没有检测到任何错误。

总结

__attribute__((cleanup(cleanup_function)))是 GCC 提供的一个强大工具,用于在变量作用域结束时自动调用清理函数。通过使用这一特性,可以编写更简洁、更安全的代码,确保资源在不再需要时被正确释放。无论是释放内存,关闭文件描述符、还是其他资源管理任务,__attribute__((cleanup_function)) 都能提供有效的解决方案。希望本文能帮助你在项目中更好地利用这一特性,提高代码的质量和可靠性。


Linux二进制 Linux编程、内核模块、网络原创文章分享,欢迎关注"Linux二进制"微信公众号
评论
  •   北京华盛恒辉作战仿真系统软件平台是现代军事领域中用于模拟作战环境、评估作战方案、训练军事人员的重要工具。这些平台通过计算机技术构建虚拟战场,支持多兵种、多武器系统的协同作战仿真,为军事决策、战术训练和装备研发提供科学依据。以下从平台类型、核心技术、应用场景及发展趋势等方面进行详细介绍。   应用案例   目前,已有多个作战仿真系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润作战仿真系统。这些成功案例为作战仿真系统的推广和应用提供了有力支持。   一、作战仿真系统软件平台
    华盛恒辉l58ll334744 2025-04-20 15:37 35浏览
  •   数字化战场:军事态势视景仿真推演系统软件解析   北京华盛恒辉军事态势视景仿真推演系统软件是现代军事领域模拟战场态势、辅助指挥决策的关键工具。伴随信息技术发展,其在提升军事训练质量、优化作战指挥决策等方面的作用愈发显著。   一、系统概述   该系统借助数字化技术,构建高精度三维战场环境,模拟各类作战场景与武器装备运行状态,为军事指挥员及作战人员打造沉浸式战场体验。系统融合地理信息系统(GIS)、计算机图形学、人工智能等多学科技术,实现战场态势实时感知、动态推演与可视化呈现。   应
    华盛恒辉l58ll334744 2025-04-20 11:24 31浏览
  •   电磁环境模拟软件系统深度解读   北京华盛恒辉电磁环境模拟软件系统是专业的技术工具,可生成、捕捉与分析电磁信号,为电气和电子设备搭建仿真测试环境。以下从功能、技术特性、应用场景、主流软件及发展趋势展开介绍。   应用案例   目前,已有多个电磁环境模拟软件系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁环境模拟软件系统。这些成功案例为电磁环境模拟软件系统的推广和应用提供了有力支持。   一、核心功能   电磁环境模拟   信号生成与处理   场景构建与仿真
    华盛恒辉l58ll334744 2025-04-21 10:21 10浏览
  • 在智能家居与物联网(IoT)技术快速发展的背景下,语音播报功能已成为烟雾报警器等安防设备提升用户体验的核心技术之一。厂家凭借其WTV、WTN、WT588F及WT2605C系列语音芯片,推出了三大烟雾报警器语音方案,覆盖传统、高集成度与智能化需求,为不同场景提供灵活选择。以下从技术特性、应用场景及行业价值三方面展开分析。一、方案对比与技术特性 方案类型核心芯片型号技术优势局限性适用场景传统分立方案WTN6/WT588F/WTV系列音质纯净,模块化设计便于维护;兼容性强,支持外接功放优化音
    广州唯创电子 2025-04-21 08:53 60浏览
  •   智慧华盛恒辉国有单位科研项目审计管理系统介绍   1、建设国有单位科研项目审计管理系统的重大意义   其深远意义体现在科研项目管理的核心环节,不仅关乎管理效能与成果质量的飞跃,还深刻影响着科研资金的优化配置、科研行为的规范性以及国家科技发展战略的顺利推进。   应用案例   目前,已有多个科研项目审计管理系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润科研项目审计管理系统。这些成功案例为科研项目审计管理系统的推广和应用提供了有力支持。   (1)强化科研项目管理的效
    华盛恒辉l58ll334744 2025-04-20 22:54 38浏览
  •   智慧华盛恒辉国有单位招标标书查重系统介绍   1、建设国有单位招标标书查重系统的重大意义   (1)保障招标过程的公正性与透明度   在国有单位复杂的招标环境中,标书查重系统犹如一把利剑,精准切割出公平竞争的道路。该系统利用自动化比对与检测技术,快速揭露投标文件中潜藏的相似或重复内容,有效遏制了围标、串标及抄袭等恶劣行为,为招标过程披上了一层公正与透明的外衣。这不仅减少了人为干预的空间,更保障了合法投标人的权益,维护了市场的健康秩序,让每一次招标都成为真正的实力较量。   应用案例
    华盛恒辉l58ll334744 2025-04-20 23:07 52浏览
  • 一、市场背景与竞争优势随着智能家居市场的爆发式增长,消费者对小家电的智能化、交互性需求显著提升。WTVxxx系列语音芯片凭借高性价比、卓越音质与功能集成度,已成为智能小家电领域的核心驱动方案。该系列芯片通过以下优势重塑行业格局:成本优化:集成MCU、语音播报、驱动控制等多功能模块,显著降低硬件成本与开发复杂度;智能化升级:支持语音交互、状态显示与智能控制,契合现代用户对高端体验的追求;快速迭代:兼容主流芯片架构,支持远程更新与硬件扩展,助力产品持续迭代。目前,WTVxxx芯片已广泛应用于扫地机器
    广州唯创电子 2025-04-21 08:32 60浏览
  •   战略仿真推演系统设计方案   一、系统概述   1.1 系统定位   北京华盛恒辉战略仿真推演系统是面向政府、企业及军事机构的决策支持工具。它通过搭建虚拟环境,模拟真实战略场景,助力用户评估不同策略的潜在影响,优化决策流程,提升战略规划的科学性与前瞻性。   应用案例   目前,已有多个战略仿真推演系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润战略仿真推演系统。这些成功案例为战略仿真推演系统的推广和应用提供了有力支持。   二、系统架构设计   2.1 总体架
    华盛恒辉l58ll334744 2025-04-20 16:27 45浏览
  •   战略仿真推演平台是一种基于计算机技术和仿真模型构建的决策支持系统,旨在通过模拟复杂战略环境,帮助决策者评估不同战略方案的效果、预测潜在风险并优化决策过程。此类平台广泛应用于军事、经济、能源、城市规划等领域,为高层决策提供科学依据。   应用案例   目前,已有多个战略仿真推演平台在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润战略仿真推演平台。这些成功案例为战略仿真推演平台的推广和应用提供了有力支持。   一、核心功能   多维度战略建模   动态推演与情景分析   
    华盛恒辉l58ll334744 2025-04-20 16:16 49浏览
  •   电磁环境模拟平台系统全解析   北京华盛恒辉电磁环境模拟平台系统是通过技术手段生成、调控和再现复杂电磁环境的专用设备,广泛应用于通信、电子、航空航天、国防等领域。其核心作用是为设备研发、测试和评估提供可控的电磁环境,验证系统在复杂电磁干扰下的性能与可靠性。   应用案例   目前,已有多个电磁环境模拟平台系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁环境模拟平台系统。这些成功案例为电磁环境模拟平台系统的推广和应用提供了有力支持。   一、系统构成   信号发生
    华盛恒辉l58ll334744 2025-04-21 09:40 43浏览
  •   国有单位科研项目审计管理系统解析   一、系统建设意义   北京华盛恒辉国有单位科研项目审计管理系统对科研项目管理至关重要,其意义贯穿管理效能提升、资金优化配置、科研合规推进等核心环节,深刻影响国家科技战略实施。   应用案例   目前,已有多个国有单位科研项目审计管理系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润国有单位科研项目审计管理系统。这些成功案例为国有单位科研项目审计管理系统的推广和应用提供了有力支持。   提升科研项目管理质效:作为数字化、智能化管理工
    华盛恒辉l58ll334744 2025-04-20 23:21 50浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦