linux gcc __attribute__

__attribute__

  • 1. 函数属性
    • 1.1 __attribute__((noreturn))
    • 1.2 __attribute__((format))
    • 1.3 __attribute__((const))
  • 2. 变量属性
    • 2.1. __attribute__((aligned))
    • 2.2. __attribute__((packed))
  • 3. 类型属性

__attribute__ 是 GCC 编译器提供的一种特殊语法,它可以用于设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。

1. 函数属性

1.1 attribute((noreturn))

__attribute__((noreturn)) 通常应用于那些“不会返回”的函数,即程序就直接在这个函数内退出了。例如:

  1. 程序异常处理

在程序遇到错误或异常时,可能需要立即终止程序并输出错误信息。这种情况下,可以使用 __attribute__((noreturn)) 注解来标记一个名为 die 的函数,以确保函数执行完之后程序不会继续运行。

void die(const char* msg) __attribute__((noreturn));void die(const char* msg) {fprintf(stderr, "Error: %s\n", msg);exit(1);
}

在上面的代码中,我们定义了一个名为 die 的函数,并使用 __attribute__((noreturn)) 注解表示该函数不会返回。在函数内部,我们使用 fprintf 打印错误信息,并调用 exit(1) 函数来终止程序。由于 die 函数被标记为 noreturn,因此编译器保证在执行完 die 函数之后程序不会继续运行。

  1. 核心转储文件生成

在 Linux 系统中,当程序异常终止时,可以通过设置 coredump 文件来捕获程序状态和内存快照等信息,以便于进行故障排查和调试。在生成核心转储文件时,可以使用 __attribute__((noreturn)) 注解来标记一个名为 abort 的函数,以确保函数执行完之后程序不会继续运行。

void abort() __attribute__((noreturn));void abort() {signal(SIGABRT, SIG_DFL);raise(SIGABRT);exit(EXIT_FAILURE);
}

在上面的代码中,我们定义了一个名为 abort 的函数,并使用 __attribute__((noreturn)) 注解表示该函数不会返回。在函数内部,我们使用 signal 设置信号处理函数为默认值,并调用 raise 来生成 SIGABRT 信号,然后再调用 exit 函数来终止程序。由于 abort 函数被标记为 noreturn,因此编译器保证在执行完 abort 函数之后程序不会继续运行。

总的来说,__attribute__((noreturn)) 通常适用于那些具有明确终止程序任务的函数,例如异常处理、断言失败、致命错误等。它可以帮助开发者更好地控制程序流程和性能,并减少潜在的漏洞和错误。

1.2 attribute((format))

__attribute__((format))用于指定函数参数的格式化字符串。它可以帮助编译器在编译时对函数调用进行检查,以确保传递给被调用函数的参数与函数定义中的格式化字符串相匹配。
使用__attribute__((format))可以帮助编译器进行静态类型检查,以便捕获在编译时可能导致格式化字符串错误的问题。例如,如果格式化字符串中指定了一个整数参数,但实际传递给函数的是一个字符串参数,编译器将发出警告或错误消息。

以下是一个使用__attribute__((format))的示例:

#include <stdio.h>void my_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));/** 模拟标准库函数printf,它接受一个格式化字符串和可变数量的参数,并将格式化后的输出打印到标准输出。* 通过使用va_list和相关的宏来处理可变参数,函数能够将格式化字符串和参数传递给vprintf函数进行输出。* 需要注意的是,这个函数没有进行格式字符串和参数的类型检查,所以在使用时需要确保格式化字符串与参数的类型和数量相匹配,以避免潜在的运行时错误。*/
void my_printf(const char *format, ...)
{// va_list是一个类型,用于存储可变数量的参数。va_list args;// va_start宏用于初始化args,使其指向可变参数列表的起始位置。第二个参数是最后一个非可变参数,即格式化字符串format。va_start(args, format);// vprintf是一个标准C函数,用于根据格式化字符串format和可变参数列表args打印输出。它与printf函数类似,但接受一个va_list参数而不是可变数量的参数。vprintf(format, args);// va_end宏用于结束对可变参数的访问,清理相关资源。va_end(args);
}int main()
{int num = 10;my_printf("The number is: %d\n", num);  // 正确的使用my_printf("The number is: %s\n", num);  // 错误的使用,编译器可能会发出警告或错误消息return 0;
}

在上面的示例中,my_printf函数使用__attribute__((format(printf, 1, 2)))来指定它的第一个参数是格式化字符串,并且函数至少接受两个参数。这样,编译器在编译时将会检查函数调用的参数是否与格式化字符串相匹配。

应用场景
__attribute__((format))的主要应用场景是在编写格式化输出函数(如printffprintf等)或格式化输入函数(如scanffscanf等)时,用于增加编译时的类型检查和错误检测。

以下是一些实际应用场景:

  1. 自定义格式化输出函数:当你需要编写自定义的格式化输出函数时,可以使用__attribute__((format))来确保传递给函数的参数与格式化字符串匹配。这有助于避免在运行时出现格式化字符串错误导致的问题,提高代码的健壮性和可靠性。

  2. 日志记录:当你编写日志记录函数时,可以使用__attribute__((format))来确保日志消息的格式化字符串与实际参数匹配。这样可以在编译时捕获潜在的日志格式错误,避免在运行时出现错误的日志输出。

  3. 静态代码分析工具:静态代码分析工具可以利用__attribute__((format))来检测代码中的潜在问题。通过分析函数调用和格式化字符串,这些工具可以检查是否存在格式化字符串与参数不匹配的情况,并生成警告或错误报告。

总之,__attribute__((format))的主要应用场景是在需要进行格式化字符串的输出或输入操作时,提供编译时的类型检查和错误检测,以提高代码的安全性和可维护性。

需要注意的是,__attribute__((format))是一个编译器特定的扩展,不是标准C或C++的一部分,因此在不同的编译器中可能会有差异。

1.3 attribute((const))

__attribute__((const))用于标记函数为纯函数(Pure Function)。纯函数是指函数的返回值仅依赖于输入参数,而不受其他因素的影响,也不会对程序的状态产生任何可观察的副作用。

以下是关于__attribute__((const))的一些要点:

  1. 纯函数属性:通过将函数标记为__attribute__((const)),指示编译器该函数是一个纯函数。这意味着函数的返回值仅由函数的参数决定,并且在同样的输入下,函数的返回值始终相同。

  2. 优化机会:将函数标记为纯函数有助于编译器进行优化。编译器可以假设对于相同的输入参数调用纯函数的两个位置,其返回值也必定相同。这种假设使得编译器可以进行常量传播(constant propagation)、公共子表达式消除(common subexpression elimination)等优化操作。

  3. 副作用限制:纯函数不应该对程序状态产生可观察的副作用。它们不应修改全局变量、静态变量,也不应进行I/O操作或内存分配等可能改变程序状态的操作。

  4. 示例用法:以下是一个示例函数,展示如何使用__attribute__((const))标记函数为纯函数:

int square(int x) __attribute__((const));int square(int x) {return x * x;
}

在上述示例中,square函数被标记为纯函数。它只依赖于输入参数x的值,并返回x的平方。由于square函数没有副作用,编译器可以进行进一步优化,例如在常量传播时使用已知的输入值。

总结:__attribute__((const))函数属性用于标记函数为纯函数,以便编译器进行优化。这可以提供更好的代码优化和可读性,并确保函数没有对程序状态产生可观察的副作用。

2. 变量属性

2.1. attribute((aligned))

__attribute__((aligned(n))是GCC和Clang编译器提供的一个属性,用于指定变量、结构体、联合体和数组的对齐方式为n字节对齐。下面是对该属性的详细解释以及几个完整示例:

__attribute__((aligned(n))属性的解释:

  • __attribute__((aligned(n))是GCC和Clang编译器的扩展语法,用于控制内存对齐方式。
  • 它可以应用于变量、结构体、联合体和数组等数据类型的声明。
  • 通过将其放置在声明之后,可以指定所需的对齐方式,其中n表示对齐的字节数。

示例:


#include <stdio.h>struct Point
{char arr[25] __attribute__((aligned(__BIGGEST_ALIGNMENT__))); // 以当前机器支持的最大字节对齐数__BIGGEST_ALIGNMENT__来对齐char数组double x;
};struct Point2
{char arr[17] __attribute__((aligned(8))); // 以8字节对齐来对齐char数组double x;
};struct Point3
{char arr[25]; double x;
}__attribute__((aligned(__BIGGEST_ALIGNMENT__))); // 以当前机器支持的最大字节对齐数__BIGGEST_ALIGNMENT__来对齐结构体int main()
{struct Point p; // 以16字节对齐的结构体变量printf("Size of Point: %zu\n", sizeof(struct Point));printf("Size of Point2: %zu\n", sizeof(struct Point2));printf("Size of Point3: %zu\n", sizeof(struct Point3));return 0;
}

运行结果:
在这里插入图片描述

attribute((aligned(n)))和#pragma pack(n)的区别
__attribute__((aligned(n)))#pragma pack(n) 都是用于控制内存对齐方式的机制,但它们之间存在一些区别:

  1. 语法:

    • __attribute__((aligned(n))) 是一种在 C 和 C++ 中使用的属性语法,直接应用于变量或结构体的声明。
    • #pragma pack(n) 是一个预处理器指令,需要放置在源代码中的适当位置。
  2. 作用范围:

    • __attribute__((aligned(n))) 可以直接应用于单个变量或结构体的声明,仅影响指定的实体。
    • #pragma pack(n) 影响其所在作用域内的所有变量或结构体的对齐方式,直到遇到另一个 #pragma pack 恢复默认对齐方式。
  3. 兼容性:

    • __attribute__((aligned(n))) 是 GNU C 和一些兼容的编译器支持的语法。它在符合标准的编译器中可能无效或产生不可预测的结果。
    • #pragma pack(n) 是一种更通用的指令,可以在多个编译器上使用,但具体行为可能会因编译器而异。
  4. 细粒度控制:

    • __attribute__((aligned(n))) 允许您对每个变量或结构体进行精确的对齐控制,可以指定不同的对齐方式。
    • #pragma pack(n) 设置了一个全局对齐方式,会对作用范围内的所有变量或结构体生效,并且无法针对特定实体进行个别设置。

2.2. attribute((packed))

attribute((packed)) 和 #pragma pack(1) 的作用是相同的,即指定结构体或变量的紧凑对齐方式。

无论是使用 attribute((packed)) 还是 #pragma pack(1),它们都会取消默认的对齐规则,使结构体或变量的成员按照紧凑方式存储在内存中,避免因对齐而导致的额外空间浪费或与其他系统的数据格式要求不匹配。


#include <stdio.h>struct Point
{char arr[25];double x  __attribute__((packed));
};int main()
{struct Point p; // 以16字节对齐的结构体变量printf("Size of Point: %zu\n", sizeof(struct Point));return 0;
}

运行结果:
在这里插入图片描述

3. 类型属性

通过使用 __attribute__,可以为函数、变量、结构体、枚举等类型添加特定的属性,以便在编译过程中进行控制或优化。

以下是一些常用的 __attribute__ 类型属性:

下面是对这几个 __attribute__ 类型属性的简要介绍:

  1. __attribute__((aligned(n))):这个属性用于指定变量或结构体的对齐方式。通过设置 __attribute__((aligned(n))),您可以将变量或结构体按照 n 字节对齐。例如,attribute((aligned(4)))` 将变量或结构体按照 4 字节对齐。

  2. __attribute__((packed)):该属性用于指定结构体或变量的紧凑对齐方式。默认情况下,编译器会根据对齐规则将结构体或变量的成员对齐到特定的边界上,以提高访问效率。使用 __attribute__((packed)) 属性可以取消对齐规则,使结构体或变量的成员以紧凑的方式存储。

  3. __attribute__((transparent_union)):透明联合是一种特殊类型的联合,允许将联合成员与外部成员具有相同的地址。使用 __attribute__((transparent_union)) 属性可以在联合类型中启用这种行为。

  4. __attribute__((unused)):该属性用于告诉编译器某个函数或变量可能未被使用。通过添加 __attribute__((unused)) 属性,可以避免编译器产生未使用变量或函数的警告。

  5. __attribute__((deprecated)):使用该属性可以将函数或变量标记为已过时。当使用被标记为过时的函数或变量时,编译器会发出警告,提醒开发者不再推荐使用。

  6. __attribute__((may_alias)):该属性用于指示编译器该类型可能与其他类型进行别名访问,即可能会将不同类型的指针视为相同类型的别名指针。这在某些特定的编程场景中可能会有用。

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

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

相关文章

论文阅读---《Unsupervised Transformer-Based Anomaly Detection in ECG Signals》

题目&#xff1a;基于Transformer的无监督心电图&#xff08;ECG&#xff09;信号异常检测 摘要 异常检测是数据处理中的一个基本问题&#xff0c;它涉及到医疗感知数据中的不同问题。技术的进步使得收集大规模和高度变异的时间序列数据变得更加容易&#xff0c;然而&#xff…

如何创建无序列表和有序列表?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 无序列表⭐ 无序列表⭐ 注意事项⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴…

CVPR 2023 | 无监督深度概率方法在部分点云配准中的应用

注1:本文系“计算机视觉/三维重建论文速递”系列之一,致力于简洁清晰完整地介绍、解读计算机视觉,特别是三维重建领域最新的顶会/顶刊论文(包括但不限于 Nature/Science及其子刊; CVPR, ICCV, ECCV, NeurIPS, ICLR, ICML, TPAMI, IJCV 等)。本次介绍的论文是:2023年,CVPR,…

[服务被植入脚本,数据泄密?数据库如何做内网访问?]

目录 前言: 数据库内网访问的方式: 使用nginx进行反向代理可以实现将外部用户的请求转发到内网中的数据库服务器上。具体步骤如下&#xff1a; 使用SSH隧道可以建立加密的连接&#xff0c;从而实现外部用户通过SSH隧道访问内网中的数据库。具体步骤如下&#xff1a; 使用端…

vcode开发go

配置环境变量 go env -w GO111MODULEon go env -w GOPROXYhttps://goproxy.cn,direct 创建文件夹 mkdir hello cd hello go mod help go mod help 初始化一个项目 go mod init hello 获取第三方包 go get github.com/shopspring/decimal 将依赖包下载到本地 go mod …

【Docker】Docker的应用场景,Docker 的优点,Ubuntu Docker 安装,使用 Shell 脚本进行安装

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

ubuntu 硬盘操作

查看移动硬盘的文件系统名 以及空间使用情况 df -hl查看硬盘的格式类型&#xff0c;以及挂载位置 df -T挂载硬盘 fdisk -l #查看磁盘信息 mount -o rw /dev/sdb1 /home/test # 挂载硬盘-o 指定挂载文件系统时的选项 ro 以只读方式挂载 rw 以读写方式挂载 注意&#xff1a;…

Java面向对象程序设计:抽象类与接口

一、抽象类 1.1 概念 使用abstract关键字定义的类称为抽象类&#xff0c;而使用这个关键字定义的方法称为抽象方法。抽象方法没有方法体&#xff0c;这个方法本身没有任何意义&#xff0c;除非它被重写&#xff0c;而承载这个抽象方法的抽象类必须被继承&#xff0c;实际上抽…

java并发ForkJoinPool

ForkJoinPool Fork/Join 框架是 Java 并发库中用于实现分治任务并行处理的工具。它基于 “工作窃取”&#xff08;work-stealing&#xff09;算法&#xff0c;可以将一个大任务拆分成多个小任务&#xff0c;并利用多线程进行并行处理。 核心方法&#xff1a; 创建 Fork/Join…

探究使用HTTP爬虫ip后无法访问网站的原因与解决方案

在今天的文章中&#xff0c;我们要一起来解决一个常见问题&#xff1a;使用HTTP爬虫ip后无法访问网站的原因是什么&#xff0c;以及如何解决这个问题。我们将提供一些实际的例子和操作经验&#xff0c;帮助大家解决HTTP爬虫ip无法访问网站的困扰。 1、代理服务器不可用 使用HT…

【Linux进阶之路】进程(上)

文章目录 前言一、操作系统加载过程二、进程1.基本概念2.基本信息①运行并观察进程②创建子进程③僵尸与孤儿进程&#xff08;父子进程衍生出来的问题&#xff09;1. 僵尸进程&#xff08;Zombie状态&#xff09;2. 孤儿进程 3.基本状态①操作系统的状态&#xff08;统一&#…

系列3-常见的高可用MySQL解决方案

高可用主要解决两个问题&#xff0c;如何实现数据共享和同步数据、如何处理failover&#xff0c;数据共享的解决方案一般是SAN&#xff0c;数据同步通过rsync和drbd技术来实现。 1、主从复制解决方案 这是MySQL自身的高可用解决方案&#xff0c;数据同步方法采用的是MySQL rep…

【图像去噪】基于混合自适应(EM 自适应)实现自适应图像去噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

目标检测中的IOU

IOU 什么是IOU?IOU应用场景写代码调试什么是IOU? 简单来说IOU就是用来度量目标检测中预测框与真实框的重叠程度。在图像分类中,有一个明确的指标准确率来衡量模型分类模型的好坏。其公式为: 这个公式显然不适合在在目标检测中使用。我们知道目标检测中都是用一个矩形框住…

VSCode CMake vcpkg 整合

VSCode 整合 CMake 调试 CMake 工程 // launch.json {"version": "0.2.0","configurations": [{"name": "(gdb) Launch","type": "cppdbg","request": "launch",// Resolved by …

如何对oracle和mysql进行 分区分表

前提&#xff1a;使用自带的分区和分表机制进行操作 oracle,mysql分区分表 分区 分区是一种将一个大的表或索引分割成多个小的部分的技术&#xff0c;每个部分称为一个分区。分区可以提高数据的管理和查询效率&#xff0c;因为可以根据不同的条件对不同的分区进行操作&#x…

小研究 - 基于 SpringBoot 微服务架构下前后端分离的 MVVM 模型(三)

本文主要以SpringBoot微服务架构为基础&#xff0c;提出了前后端分离的MVVM模型&#xff0c;并对其进行了详细的分析以及研究&#xff0c;以此为相关领域的工作人员提供一定的技术性参考。 目录 6 互联网应用开发架构分析 6.1 微服务架构与单体架构 6.1.1 系统更改部署 6.1…

关于什么是框架

框架&#xff08;Framework&#xff09;是一个框子——指其约束性&#xff0c;也是一个架子——指其支撑性。 IT语境中的框架&#xff0c;特指为解决一个开放性问题而设计的具有一定 性的支撑结构。在此结构上约束可以根据具体问题扩展、安插更多的组成部分&#xff0c;从而更迅…

lz4 与 lz77 压缩算法举例

lz4算法 abcd efab cdeh 压缩过程&#xff1a; 以长度&#xff14;为滑窗&#xff0c;&#xff11;为步长&#xff0c;对abcd计算hash存入hash table&#xff0c;计算 bcde, cdef,defa,efab,fabc的 hash 分别加入 hash table&#xff0c;下一个滑窗 abcd 找到了匹配&#xf…

TS学习01-基本数据类型

基础类型 数组 第一种&#xff1a; 元素类型[] let arr: number[] [1,2,3]第二种: 数组泛型-Array<元素类型> let arr: Array<number> [1,2,3]元组 Tuple 表示一个已知元素数量和类型的数组 let arr: [string, number] a [RenNing, 18]当访问越界元素&…