C语言再学习 -- __attribute__详解

news2025/7/20 21:08:11

一、attribute 介绍

__attribute__是一个编译属性,用于向编译器描述特殊的标识、错误检查或高级优化。它是GNU C特色之一,系统中有许多地方使用到。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)等。

二、attribute 格式

attribute 前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__ 属性规范。

格式如下:

__attribute__ ((attribute-list)) 

三、指定函数的属性

参看:GNU 声明函数的属性

在 GNU C 中,您声明有关程序中调用的函数的某些内容,这有助于编译器优化函数调用并更仔细地检查您的代码。

以下属性目前在所有目标函数的定义: aligned, alloc_size, noreturn, returns_twice, noinline, noclone, always_inline, flatten, pure, const, nothrow, sentinel, format, format_arg, no_instrument_function, no_split_stack, section, constructor, destructor, used, unused, deprecated, weak, malloc, alias, ifunc, warn_unused_result, nonnull, gnu_inline, externally_visible, hot, cold, artificial, error and warning.

四、指定类型的属性

参看:GNU 指定类型的属性

关键字允许您在定义此类类型时__attribute__指定struct和类型的特殊属性。union此关键字后跟双括号内的属性规范。目前为类型定义了七个属性:alignedpackedtransparent_unionunuseddeprecatedvisibilitymay_alias

五、指定变量的属性

参看:GNU 指定变量的属性

关键字__attribute__允许您指定变量或结构字段的特殊属性。

目前为变量定义的属性:aligned,cleanupcommondeprecatedmodepackedsectionsharedtls_modelunusedusedvector_sizeselectanyweakdllimportdllexport

六、常见属性

1. aligned (alignment)

指定函数的属性:

此属性指定函数的最小对齐方式,以字节为单位。不能使用此属性减少函数的对齐,只能使用此属性增加函数的对齐。请注意,对齐属性的有效性可能受到链接器固有限制的限制。在许多系统上,连接器只能安排函数对齐到某个最大对齐。

指定类型的属性:

此属性指定指定类型变量的最小对齐方式(以字节为单位)。例如,

 struct S { short f[3]; } __attribute__ ((aligned (8)));
 typedef int more_aligned_int __attribute__ ((aligned (8)));

强制编译器确保(尽可能)每个类型为struct Smore_alignd_int的变量至少在8字节的边界上被分配和对齐。在SPARC上,将struct S的所有变量对齐到8字节边界,允许编译器在将struct S的一个变量复制到另一个变量时使用lddstd(双字加载和存储)指令,从而提高运行时效率。

请注意,ISO C标准要求任何给定structunion类型的对齐至少是相关structunion所有成员对齐的最低公倍数的完全倍数。这意味着您可以通过将aligned属性附加到此类类型的任何一个成员来有效地调整structunion类型的对齐方式,但上面示例中所示的符号是一种更明显、直观和可读的方式,用于请求编译器调整整个结构或联合类型的对齐方式。

与前面的示例一样,您可以显式地指定希望编译器用于给定structunion类型的对齐方式(以字节为单位)。或者,您可以省略对齐因子,只要求编译器将类型对齐为您正在编译的目标机器的最大有用对齐。例如,你可以这样写:

struct S { short f[3]; } __attribute__ ((aligned));

每当在aligned属性规范中遗漏对齐因子时,编译器会自动将该类型的对齐方式设置为正在编译的目标机器上任何数据类型所使用的最大对齐方式。这样做通常可以使复制操作更有效,因为编译器可以使用任何指令复制最大的内存块,当执行复制到或从具有这样对齐的类型的变量时。

在上面的例子中,如果每个short的大小是2字节,那么整个struct S类型的大小是6字节。大于或等于2的最小幂是8,因此编译器将整个struct S类型的对齐设置为8字节。

请注意,尽管您可以要求编译器为给定类型选择省时的对齐方式,然后只声明该类型的独立对象,但编译器选择省时对齐方式的能力仅在计划创建具有相关(高效对齐)类型的变量数组时才有用。如果声明或使用有效对齐类型的变量数组,那么程序很可能也会对指向相关类型的指针进行指针算术(或下标,这相当于同样的事情),而且编译器为这些指针算术操作生成的代码对于有效对齐类型通常比其他类型更有效。

请注意,aligned属性的有效性可能受到链接器固有限制的限制。在许多系统上,链接器只能安排变量对齐到某个最大对齐。(对于某些连接器,支持的最大对齐可能非常非常小。)如果你的链接器只能对变量进行最多8个字节的对齐,那么在__attribute__中指定aligned(16)仍然只能为你提供8个字节的对齐。

指定变量的属性

此属性指定变量或结构字段的最小对齐方式,以字节为单位。例如,

int x __attribute__ ((aligned (16))) = 0;

导致编译器在16字节边界上分配全局变量x。在68040上,这可以与asm表达式一起使用来访问move16指令,该指令需要16字节对齐的操作数。

还可以指定结构字段的对齐方式。例如,要创建一个双字对齐的int对,你可以这样写:

 struct foo { int x[2] __attribute__ ((aligned (8))); };

这是创建具有double memberunion的另一种选择,它迫使union以双字对齐。

与前面的示例一样,您可以显式地指定希望编译器为给定变量或结构字段使用的对齐方式(以字节为单位)。或者,您可以省略对齐因子,只要求编译器将变量或字段对齐为您正在编译的目标体系结构的默认对齐方式。默认对齐方式对于所有标量类型已经足够,但对于支持向量操作的目标上的所有向量类型可能还不够。对于特定的目标ABI,默认对齐方式是固定的。

aligned属性只能增加对齐;但您也可以通过指定packed来减少它。

请注意,对齐属性的有效性可能受到链接器固有限制的限制。在许多系统上,链接器只能安排变量对齐到某个最大对齐。(对于某些连接器,支持的最大对齐可能非常非常小。)如果你的链接器只能对变量进行最多8个字节的对齐,那么在__attribute__中指定aligned(16)仍然只能为你提供8个字节的对齐。

扩展:

结构体内存对齐与补齐

一个存储区的地址一定是它自身大小的整数倍(双精度浮点类型的地址只需要4的整数倍就行了),这个规则也叫数据对齐,结构体内部的每个存储区通常也需要遵守这个规则。数据对齐可能造成结构体内部存储区之间有浪费的字节。结构体的大小一定是内部最大基本类型存储区大小的整数倍,这个规则叫数据补齐。

#include <stdio.h>  
typedef struct  
{  
    char ch;  
    int num;  
    char ch1;  
}str;  

int main (void)  
{  
    printf ("sizeof (str) is %d\n", sizeof (str));  
    return 0;  
}  
输出结果:  
sizeof (str) is 12  

变量属性与类型属性举例

下面的例子中使用__attribute__属性定义了一些结构体及其变量,并给出了输出结果和对结果的分析。

struct p
{
  int a;
  char b;
  char c;
}__attribute__((aligned(4))) pp;

struct q
{
  int a;
  char b;
  struct n qn;
  char c;
}__attribute__((aligned(8))) qq;

int main()
{
  printf("sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\n",
	sizeof(int),sizeof(short),sizeof(char));
  printf("pp=%d,qq=%d \n", sizeof(pp),sizeof(qq));
  return 0;
}

输出结果:
sizeof(int)=4,sizeof(short)=2.sizeof(char)=1
pp=8,qq=24

分析:
sizeof(pp):
sizeof(a)+ sizeof(b)+ sizeof©=4+1+1=6<23=8= sizeof(pp)
sizeof(qq):
sizeof(a)+ sizeof(b)=4+1=5
sizeof(qn)=8;即qn是采用8字节对齐的,所以要在a,b后面添3个空余字节,然后才能存储qn,
4+1+(3)+8+1=17
因为qq采用的对齐是8字节对齐,所以qq的大小必定是8的整数倍,即qq的大小是一个比17大又是8的倍数的一个最小值,由此得到17<24+8=24= sizeof(qq)

2. section-name

指定变量的属性

通常,编译器将它生成的对象放在databss这样的部分中。但是,有时需要额外的部分,或者需要某些特定的变量出现在特定的部分中,例如映射到特殊的硬件。section属性指定变量(或函数)位于特定的部分中。例如,这个小程序使用了几个特定的节名:

struct duart a __attribute__ ((section ("DUART_A"))) = { 0 };
struct duart b __attribute__ ((section ("DUART_B"))) = { 0 };
char stack[10000] __attribute__ ((section ("STACK"))) = { 0 };
int init_data __attribute__ ((section ("INITDATA")));

main()
{
/* Initialize stack pointer */
init_sp (stack + sizeof (stack));

/* Initialize initialized data */
memcpy (&init_data, &data, &edata - &data);

/* Turn on the serial ports */
init_duart (&a);
init_duart (&b);
}

将section属性用于全局变量,而不是局部变量,如示例所示。

你可以将section属性与初始化或未初始化的全局变量一起使用,但是链接器要求每个对象都定义一次,除非未初始化的变量暂时放在common(或bss)部分中,并且可以多次“defined”。使用section属性将改变变量进入的部分,如果未初始化的变量有多个定义,则可能导致链接器发出错误。可以使用-fno-common标志或nocommon属性强制初始化变量。

扩展

一个可执行目标文件,它主要由代码段数据段BSS 段构成。代码段主要存放编译生成的可执行指令代码,数据段BSS 段用来存放全局变量、未初始化的全局变量。代码段数据段BSS 段构成了一个可执行文件的主要部分。

参看:UNIX再学习 – 内存管理

img

参看:GCC 中的强符号、弱符号(-fno-common)

链接器中的全局符号可分为两种:强符号(Strong symbols),弱符号(Weak symbols)。GCC语法中使用__attribute__((weak))来声明这个符号是弱符号的。

而对于全局变量来说,如果初始化了不为0的值,那么该全局变量则被保存在data段,如果初始化的值为0,那么将其保存在bss段,如果没有初始化,则将其保存在common段,等到链接时再将其放入到bss段。关于第三点不同编译器行为会不同,有的编译器会把没有初始化的全局变量直接放到bss段。

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

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

相关文章

JavaScript 如何优雅地获取多层级response中的某个深层次字段 ?. 可选链条(Optional chaining)

文章目录一句话场景&#xff1a;从一个多层级对象中拿一个处在深层次位置的字段MDN 可选链搜索引擎使用一句话 var marriedFlag response.data.userList[0].married; // 如果中间某个对象为空&#xff0c;会报Errorvar marriedFlag response?.data?.userList[0]?.married…

外贸新手找客户的开发信修炼之旅(一)

开发信是一种传统的开发海外客户的方式&#xff0c;相信即便是外贸新手也或多或少有所耳闻&#xff0c;甚至已经通过邮件开发到了一些有意向的客户&#xff0c;但有时也会遇到开发信效果不好的情况&#xff0c;收到的回复寥寥无几。其实说白了开发信的本质与派发传单相同&#…

李开复已经对美图公司失去耐心,并在美图公司身上损失惨重

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经经过对美图公司&#xff08;01357&#xff09;的投资人回报、产品、业务结构、战略、财务业绩、估值等方面进行了研究&#xff0c;认为美图这家公司不行&#xff0c;非常不看好&#xff0c;以下是理由供你参考。一…

10 Seata配置Nacos注册中心和配置中心

Seata配置Nacos注册中心和配置中心 Seata支持注册服务到Nacos&#xff0c;以及支持Seata所有配置放到Nacos配置中心&#xff0c;在Nacos中统一维护&#xff1b; 高可用(集群)模式下就需要配合Nacos来完成: 具体配置如下 注册中心 Seata-server端配置注册中心&#xff0c;…

【洛谷 P1219】[USACO1.5]八皇后 Checker Challenge 题解(深度优先搜索+回溯法)

[USACO1.5]八皇后 Checker Challenge 题目描述 一个如下的 666 \times 666 的跳棋棋盘&#xff0c;有六个棋子被放置在棋盘上&#xff0c;使得每行、每列有且只有一个&#xff0c;每条对角线&#xff08;包括两条主对角线的所有平行线&#xff09;上至多有一个棋子。 上面的布…

13_MySQL中的约束

目录 1. 约束(constraint)概述 1.1 为什么需要约束 1.2 什么是约束 1.3 约束的分类 2. 非空约束 2.1 作用 2.2 关键字 2.3 特点 2.4 添加非空约束 2.5 删除非空约束 3. 唯一性约束 3.1作用 3.2 关键字 3.3 特点 3.5 关于复合唯一约束 4. 主键(PRIMARY KEY)约束 4.1 作用 4.2 关…

【Django】Hello,DJango!

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

如何实现报表可视化,有没有工具推荐

随着数据量的不断增长&#xff0c;如何更好地进行数据分析和可视化已成为企业和组织面临的重要挑战。实现报表可视化是一个很好的解决方案&#xff0c;它可以帮助用户更好地理解和分析数据&#xff0c;发现趋势和模式&#xff0c;并支持数据驱动的决策。本文将介绍如何实现报表…

现代卷积神经网络(NiN),并使用NIN训练CIFAR10的分类

专栏&#xff1a;神经网络复现目录 本章介绍的是现代神经网络的结构和复现&#xff0c;包括深度卷积神经网络&#xff08;AlexNet&#xff09;&#xff0c;VGG&#xff0c;NiN&#xff0c;GoogleNet&#xff0c;残差网络&#xff08;ResNet&#xff09;&#xff0c;稠密连接网络…

【3.7】Redis数据类型、CPU缓存一致性、哈希表

文章目录数据类型篇StringListHashSetZsetBitMapHyperLogLogGEOStreamCPU 缓存一致性CPU是如何执行任务的&#xff1f;什么是软中断&#xff1f;为什么0.1 0.2不等于0.3&#xff1f;哈希表数据类型篇 String String 是最基本的 key-value 结构&#xff0c;key 是唯一标识&…

03 | 授权服务:授权码和访问令牌的颁发流程是怎样的? 笔记

03 | 授权服务&#xff1a;授权码和访问令牌的颁发流程是怎样的&#xff1f; 授权服务的工作过程 小兔软件需要去到京东的平台那里”备案“注册&#xff0c;京东商家开放平台就会给小兔软件 app_id 和 app_secret 等信息&#xff0c;以方便后面授权时的各种身份校验&#xff0…

scratch绘制雷达 电子学会图形化编程scratch等级考试三级真题和答案解析2022年9月

目录 scratch绘制雷达 一、题目要求 1、准备工作 2、功能实现 二、案例分析

阶段二12_面向对象高级_继承1

一.继承的入门介绍 (1)继承的概念理解 让类与类之间产生关系&#xff08;子父类关系&#xff09;&#xff0c;子类可以直接使用父类中非私有的成员 (2)通过extends关键字实现继承 格式&#xff1a;public class 子类名 extends 父类名 { } 范例&#xff1a;public class Zi e…

Grafana 如何使用本地CSV文件作为数据源

Grafana提供了一个插件&#xff0c;可以把CSV文件作为数据源&#xff0c;关于CSV插件的说明&#xff0c;可以参考&#xff1a;https://grafana.com/grafana/plugins/marcusolsson-csv-datasource/?tabinstallation。我是在本地使用命令行grafana-cli plugins install marcusol…

通过45人!1-2月,誉天红帽RHCE学员再创佳绩!

学习的喜悦在于结果&#xff0c;也在于过程&#xff1b;在于取得成功时的豁然开朗&#xff0c;也在于持之以恒后的层层递进。结果固然重要&#xff0c;但在求知过程中获得的满足感&#xff0c;也同样让人乐在其中。 RHCE的学习过程就充满了这样的喜悦。对每一行命令的理解、对每…

【Linux学习】日积月累——调试器gdb的使用教程

一、背景 gdb是一款强大的命令行调试工具&#xff0c;可以形成执行程序、脚本。只需要几个简单的命令&#xff0c;就能够实现Windows环境下VC等IDE的图形化调式工具的功能。 调试的相关常识&#xff1a; 程序的发布方式有两种&#xff0c;debug模式和release模式&#xff1b;L…

197.Spark(四):Spark 案例实操,MVC方式代码编程

一、Spark 案例实操 1.数据准备 电商网站的用户行为数据,主要包含用户的 4 种行为:搜索,点击,下单,支付 样例类: 2. Top10 热门品类 先按照点击数排名,靠前的就排名高;如果点击数相同,再比较下单数;下单数再相同,就比较支付数。 我们有多种写法,越往后性能越…

【Linux开发笔记】《Linux嵌入式开发从0到1》(一):初探Linux——与Linux的初次相遇

1.什么是Linux Linux就是一个操作系统&#xff0c;就是一个开源、自由的操作系统&#xff0c;就是一个免费使用和自由传播的类UNIX操作系统&#xff0c;就是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。 简单来讲&#xff0c;Linux就是一个操作系统而已… …

React的Hooks

React Hooks useState useMemo 和usecallback Hooks显示的指明因变量有什么好处 当使用时&#xff0c;y与changeX会被缓存下来&#xff0c;只要x不变&#xff0c;始终读取的是缓存的值&#xff0c; 如果不使用时&#xff0c;每次函数组件执行时&#xff0c;实际会基于x&#xf…

计算机写论文时,怎么引用文献? - 易智编译EaseEditing

首先需要清楚哪些引用必须注明[1]&#xff1a; 任何直接引用都要用引号并注明来源&#xff1b; 任何不是自己的口头或书面的观点、解释和结论都应注明来源&#xff1b; 即使不用原话&#xff0c;但是他人的思路、概念或观点也应注明&#xff1b; 不要为了适合你的观点修改原…