C语言的attribute机制
1. __attribute__作用及使用方法
在Linux内核中经常会遇到这么一类的定义:就是在函数、变量、或者数据类型里面添加__attribute__,对于内核的初学者来说,往往不懂这些定义是什么意思,遇到此类的定义往往需要查找半天,导致学习进度延误。
下面就从__attribute__的作用,约束方法以及使用方法和使用实例上来给大家讲解。
1.1 __attribute__的作用:
设置函数、变量以及数据类型的属性。
之前大家可能会遇到过:在C语言中对于函数或者变量重复定义的问题,attribute机制可以很好的解决这类的冲突问题;C语言中使用main函数作为入口函数,通常大家理解的在main函数之前,或者main函数结束之后可能不会再运行什么函数了,引入attribute机制就可以解决这类的问题;对于函数中可能直接终止的执行进行不恰当的调用会引起程序无故终止,attribute机制也可以解决这类的问题。
1.2 __attribute__使用方法:
在函数、数据、数据类型的定义之后,定义的顿号之前。语法格式为:__attribute__((attr_list))请注意在__attribute__后一定是两组小括号,后面跟着我们要设置属性的关键字。attribute英文字符的下划线是两个。
比如我们可以设置:
void func(void ) __attribute__((attr_list));
int num __attribute__((attr_list));
struct test { int number; } __attribute__((attr_list))
本文章将会根据__attribute__针对函数属性、变量属性数据类型属性一一用实例讲解。根据gnu的attribute介绍一章,链接如下:gnu Function attribute
gnu Variable attribute
2 函数属性设置
gnu对于函数属性主要设置的关键字如下:
alias: 设置函数别名。aligned: 设置函数对齐方式。always_inline/gnu_inline: 函数是否是内联函数。constructor/destructor:主函数执行之前、之后执行的函数。format:指定变参函数的格式输入字符串所在函数位置以及对应格式输出的位置。noreturn:指定这个函数没有返回值。请注意,这里的没有返回值,并不是返回值是void。而是像_exit/exit/abord那样执行完函数之后进程就结束的函数。weak:指定函数属性为弱属性,而不是全局属性,一旦全局函数名称和指定的函数名称命名有冲突,使用全局函数名称。
2.1 函数的constructor/destructor属性
一般认为,在C语言中,main函数是函数的执行起点和终点,在main函数之前和之后都不会执行什么额外的步骤。但是gnu引入的constructor和destructor的attribute属性关键字,可以让C函数在执行之前,和执行之后分别执行特定的函数。
编译以下实例,然后执行。
//main.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
static __attribute__((constructor))
before(void)
{printf("before main\n");
}static __attribute__((destructor))
after(void)
{printf("after main\n");
}int main(void)
{printf("in main\n");return EXIT_SUCCESS;
}
我们可以看到以下执行结果:
before main
in main
after main
在代码中的main函数里面,我们没有使用before和after两个函数,但是在实际执行中before函数在main函数之前执行,after函数在main函数之后执行。这和before和after函数分别使用了attribute属性有关。
2.2 函数的noreturn属性
函数的noreturn属性可以告诉编译器,这个函数是没有返回值的,甚至默认不返回值也是不可以的。
include <stdio.h>
#include <stdlib.h>
#include <unistd.h>void noret(void)
__attribute__((noreturn));void noret(void)
{}int main(void)
{noret();return 0;
}
如以上代码,我们可以看到noret函数在定义的时候使用了noreturn属性,函数里面什么也没有做,相当于是个空函数,但是空函数使用了默认返回值void。如果我们编译的话,会出现以下警告:
main.c: In function ‘noret’:
main.c:12:1: warning: ‘noreturn’ function does return [enabled by default]}^
上述警告告诉我们,这个函数设置的noreturn属性,但是的确返回有返回值。空函数默认返回的void空类型空数据。所以说有返回值。
如果把noret函数里面增加noreturn类型的库函数,或者把noreturn属性去掉,就不会再出现错误了,修改如下:
void noret(void)
{_exit(0);
}
2.3 函数weak属性
函数的weak属性比较有意思,它的作用在有名称冲突的函数中,如果我们在使用中有两个函数名称是一样的,我们编译器会报告给我们名称冲突的错误。如果其中一个函数使用了weak属性,我们的编译器就会把不含有weak的函数名称编译进入我们的文件里面。
实例如下:
//test.c
#include "test.h"
#include <stdio.h>
int weak_func(void)
{printf("this is in test weak function\n");return 0;
}
//test.h
#ifndef __test_h_ #define __test_h_int weak_func(void);#endif
//main.c
#include <stdio.h>
#include "test.h"//extern int weak_func(void) __attribute__((weak));
int weak_func(void)
{printf("this is in main weak function\n");return 0;
}int main(void)
{weak_func();return 0;
}
上面的函数编译是编译不通过的,编译结果如下:
gcc main.c test.h test.c
/tmp/cciED8ZA.o: In function `weak_func':
test.c:(.text+0x0): multiple definition of `weak_func'
/tmp/ccZwUE37.o:main.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
显示名称冲突,如果把main.c里面的extern int weak_func(void) __attribute__((weak));去掉注释,则可以编译过,使用的是test.c文件里面的weak_func。
2.4 函数format属性
format属性是在使用变长参数指定格式化字符串的时候使用的比较多。可以让编辑器检查格式化的字符串使用的是否正确。
format使用格式如下:
format (archetype, string-index, first-to-check)
archetype:指定参照哪个函数的格式化字符串:printf、scanf、strftime....
string-index:指定格式化字符串在函数的第几个参数。比如:“%d %s\n”这些参数在函数的第几个位置。
first-to-check:指定格式化输入的字符串在函数参数中开始的位置。
如下代码:
#include <stdio.h>void myprintf(const char * format,...)
__attribute__((format(printf,1,2)));
void myprintf(const char * format,...)
{printf("%s", format);
}int main(void)
{myprintf("abc%d\n", 1);myprintf("abc%s\n", "abc");myprintf("abc%s\n", 1);myprintf("%s %d\n", 2, 1);return 0;
}
myprintf定义时候指定参照printf的格式化字符串,1代表指定检查格式化字符串的位置,2指定参照字符串开始检查的位置。
我们
C语言的attribute机制相关推荐
- 《Java疯狂讲义》(第3版)学习笔记 2 - Java语言的运行机制
内容 1.高级语言的运行机制 2.Java 语言的运行机制 1.高级语言的运行机制 高级语言主要分为编译型语言和解释型语言两类. 编译型语言是指使用专门的编译器.针对特定平台(操作系统)将高级语言源代 ...
- SQL语言的事务机制_转摘
什么是数据库事务 数据库事务是指作为单个逻辑工作单元执行的一系列操作. 设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: · 更新客户所购商品的库存信息 · 保存客户付款信息--可能 ...
- 【C语言基础】C语言异常捕获机制 - assert
C语言异常捕获机制 - assert 快速入门 想快速入门该模块请访问:介绍,数据接口,示例代码 介绍 通常一个良好的代码功能运行环境都有功能运行前检查和运行后检查两个方面.C语言中提供了assert ...
- 【C语言基础】C语言异常捕获机制 - setjmp
C语言异常捕获机制 - setjmp 快速入门 想快速入门该模块请访问:介绍,数据接口,示例代码 介绍 C语言没有C++或Java的异常捕获机制,但可以通过setjmp/longjmp实现类似的效果: ...
- Atitit.跨语言异常转换机制 java c# php到js的异常转换
Atitit.跨语言异常转换机制 java c# php到js的异常转换 1. bizEx 直接抓取,然后js catchEX1 2. Chkec runtimeEx1 3. Other异常..J ...
- Java语言基础-反射机制、正则表达式
反射机制 反射机制是在运行状态中,对于任意一个类,都能知道这个类(class文件)的所有属性和方法. 对于任意一个对象,都能调用它的任意一个方法和属性. 这种动态获取信息以及动态调用对象的方法的功能称 ...
- C语言内存管理机制精讲-高手必修课视频教程-黄强-专题视频课程
C语言内存管理机制精讲-高手必修课视频教程-384人已学习 课程介绍 在企业级项目开发中一个非常重要的设计就是如何有效地管理内存资源.在C语言中,关于内存管理的知识点比较多,如函数变量 ...
- Java语言的运行机制
一.高级语言的运行机制 我们编程都是用的高级语言(写汇编和机器语言的大牛们除外),计算机不能直接理解高级语言,只能理解和运行机器语言,所以必须要把高级语言翻译成机器语言,计算机才能运行高级语言所编写的 ...
- java语言的实现机制_JAVA语言之Java NIO的工作机制和实现原理介绍
本文主要向大家介绍了JAVA语言之Java NIO的工作机制和实现原理介绍,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 前言 本文只简单介绍NIO的原理实现和基本工作流程 I/O和 ...
最新文章
- spring + Quartz定时任务配置
- Struct2小结:
- bytes用str转还是用decode
- Oracle 中control_file_record_keep_time参数的解释
- PAT (Basic Level) Practice (中文)1003 我要通过! (20 分)
- 计算机修改文字试题,计算机文字处理试题.doc
- C#LeetCode刷题之#69-x 的平方根(Sqrt(x))
- 每天一道剑指offer-把数组排成最小的数
- 带圆圈的数字和markdown常用表达式记录
- 【君思智慧园区】物业管理系统解决方案
- xdg在Linux中的用法,linux – 如何使用xdg-mime命令 - 程序园
- 电信物联卡稳定的apn接入点_0月租的电信纯流量卡怎么样?
- python从字符串中提取指定的内容
- jbox弹窗_Jquery多功能提示通知弹出对话框插件jBox中文文档
- 热闹之后,香港是否会成为Web3的“应许之地”?
- 江苏辖区农商银行2020年(科技类)
- 红米note3全网通版刷机救砖 9008强刷(无需短接)
- 汤姆斯的天堂梦_NOI导刊2010提高(05)【洛谷P1796】
- Vue 开发环境搭建(Mac 版)
- PVST的简单应用及其配置