概述
接触Linux一年多的时间,发现自己的技术水平还在原地打转,很不爽。想办法分析原因,发现在看系统代码中很多基础的东西都不知道,追着追着就追不下去了,根本看不懂啊。。。也许以后方向会出现变化,但是暂且不管,遇弱则恶补!
开个博客,在这里记录每次学习的内容,以及自己的理解。权当给自己留个脚印!希望能坚持住!
__attribute__,不知道是干嘛用的,有一次被面试的时候也提到这个词,当时问了static,violate等等。__attribute__ 是GNUC的一大特色!
一:基础认识
作用:设置各种属性值,例如函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
使用格式:__attribute__(attribute_list),有人说这个格式是放在声明之后,“;”之前,不知道这个是不是规定,还是说其他格式也可以?我看到的代码中有不同的情况(这个问题有待后续确认)。例如,函数的属性设置
void __attribute__((noreturn)) protected_mode_jump(u32 entrypoint, u32 bootparams);
先不用管属性值,只看格式,这个地方是放在函数返回值类型和函数名之间的!
不过在设置变量的属性的时候,确实是放在声明之后,“;”之前。例如下面的例子
union c2wr_srq_destroy {
struct c2wr_srq_destroy_req req;
struct c2wr_srq_destroy_rep rep;
} __attribute__((packed)) ;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上述东西的例子,只是在linux源码中随便搜索得到的。解决了基本概念问题,下面疑惑的就是noreturn,packed等属性值是什么意思了!
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
二:属性值介绍
函数属性值包括noreturn
,noinline
,always_inline
,pure
,const
,nothrow
,sentinel
,format
,format_arg
,no_instrument_function
,section
,constructor
,destructor
,used
,unused
,deprecated
,weak
,malloc
,alias
,warn_unused_result
andnonnull,当然也有其他的特定系统定义的一些!
section
这个属性值也支持变量属性和类型属性!
下面介绍几个常看到的属性。
1.__attribute__ noreturn ---- 函数属性
---- 函数属性//4-6 没写出来
4.__attribute__ weak
1:__attribute__((noreturn))
比如一个函数
int foo(void){
return 0;
}
调用的时候这样调用
int main(void){
foo();
return 0;
}
这个时候编译器就会warning,因为定义了一个有返回值的foo函数,却可能没有返回值,编译器不知道该怎么办了,就报出里warning!
但是如果把int foo(void)函数修改为int __attribute__((noreturn)) foo(void),就不会出现上述报警了!
2:__attribute__((packed))
使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节(one byte)对齐,对域(field)是位(one bit)对齐!
__attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。这个功能是跟操作系统没关系,跟编译器有关!
https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes
导致很晦涩难懂,甚至有的都是错误的!!
在这里举例子说明这个属性(ubuntu 平台下测试):
1 #include <stdio.h> 2 3 struct test{ 4 char a; 5 int x[2];//__attribute__((packed)); 6 }; 7 8 int main(void) 9 { 10 printf("sizeof(int) = %dn",sizeof(int)); 11 printf("sizeof(struct test) = %dn",sizeof(struct test)); 12 return 0; 13 }
上述加不加__attribute__((packed)),第二条打印的结构是不一样的,加的话,sizeof(struct test) = 9;如果不加,sizeof(struct test) = 12!其实这个属性就是设置对齐方式的。不加的话,编译器按照4字节对齐方式,不足4字节,按4字节计算! (对这句话,突然有种很熟悉的感觉。。。在C语言面试技巧里面经常出现这种题目,考对齐方式的!)
加的话,编译器会按照最小的对齐方式对齐,所以,上述程序就会按照char(1个字节)对齐,所以输出的结果就是9!
3:__attribute__ const
该 属性只能用于带有数值类型参数的函数上。当重复调用带有数值参数的函数时,由于返回值是相同的,所以此时编译器可以进行优化处理,除第一次需要运算外,其 它只需要返回第一次的结果就可以了,进而可以提高效率。该属性主要适用于没有静态状态(static state)和副作用的一些函数,并且返回值仅仅依赖输入的参数。例子:
用gcc -o const const.c后运行const, inc(10)就会输出两次。#include <stdio.h> int __attribute__((const)) inc(int x) { printf("%s(%d)n", __FUNCTION__, x); return x + 1; } int inc2(int x) { printf("%s(%d)n", __FUNCTION__, x); return x + 1; } int main(void) { int i, j; i = inc(10); j = inc(10); printf("%d %dn", i, j); i = inc2(10); j = inc2(10); printf("%d %dn", i, j); return 0; }
运行gcc -O -S const_test.c 然后会生成const_test.s,打开const_test.s就可以看到以下内容,看inc1被调用几次!
.file "const_test.c" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "%s(%d)n" .text .globl inc .type inc, @function inc: .LFB22: .cfi_startproc pushl %ebx .cfi_def_cfa_offset 8 .cfi_offset 3, -8 subl $24, %esp .cfi_def_cfa_offset 32 movl 32(%esp), %ebx movl %ebx, 12(%esp) movl $__FUNCTION__.1873, 8(%esp) movl $.LC0, 4(%esp) movl $1, (%esp) call __printf_chk leal 1(%ebx), %eax addl $24, %esp .cfi_def_cfa_offset 8 popl %ebx .cfi_def_cfa_offset 4 .cfi_restore 3 ret .cfi_endproc .LFE22: .size inc, .-inc .globl inc2 .type inc2, @function inc2: .LFB23: .cfi_startproc pushl %ebx .cfi_def_cfa_offset 8 .cfi_offset 3, -8 subl $24, %esp .cfi_def_cfa_offset 32 movl 32(%esp), %ebx movl %ebx, 12(%esp) movl $__FUNCTION__.1877, 8(%esp) movl $.LC0, 4(%esp) movl $1, (%esp) call __printf_chk leal 1(%ebx), %eax addl $24, %esp .cfi_def_cfa_offset 8 popl %ebx .cfi_def_cfa_offset 4 .cfi_restore 3 ret .cfi_endproc .LFE23: .size inc2, .-inc2 .section .rodata.str1.1 .LC1: .string "%d %dn" .text .globl main .type main, @function main: .LFB24: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 pushl %ebx andl $-16, %esp subl $16, %esp movl $10, (%esp) .cfi_offset 3, -12 call inc movl %eax, 12(%esp) movl %eax, 8(%esp) movl $.LC1, 4(%esp) movl $1, (%esp) call __printf_chk movl $10, (%esp) call inc2 movl %eax, %ebx movl $10, (%esp) call inc2 movl %eax, 12(%esp) movl %ebx, 8(%esp) movl $.LC1, 4(%esp) movl $1, (%esp) call __printf_chk movl $0, %eax movl -4(%ebp), %ebx leave .cfi_restore 5 .cfi_def_cfa 4, 4 .cfi_restore 3 ret .cfi_endproc .LFE24: .size main, .-main .section .rodata .type __FUNCTION__.1873, @object .size __FUNCTION__.1873, 4 __FUNCTION__.1873: .string "inc" .type __FUNCTION__.1877, @object .size __FUNCTION__.1877, 5 __FUNCTION__.1877: .string "inc2" .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3" .section .note.GNU-stack,"",@progbits
自己经常看别人博客的时候,看到很长的就看不下去了,这个就先写这么多吧,其他的有不懂的时候就去到
https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes
去看!
以上的表述只是自己的理解,如果有错误的地方,敬请谅解,顺便烦请回复,好让我做更改,以免有人看到的时候误人子弟!
最后
以上就是帅气睫毛膏为你收集整理的(一)__attribute__理解的全部内容,希望文章能够帮你解决(一)__attribute__理解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复