C语言
如果你读过Linux内核源码,那你一定经常会看到__attribute__。
struct hci_ev_si_device {
__u16 event;
__u16 dev_id;
} __attribute__ ((packed));
后面跟上两个括号,括号里面一般会写packed aligned unused等等。
这个语法我们在写代码的时候很少遇到,今天就来简单的了解下它的用法。
attribute翻译过来是属性的意思,所以它的作用就是用来设置函数、变量或者数据类型的属性。
下面通过代码来演示下它的书写规则。
我们都知道C语言的入口是主函数,如果想要在主函数之前或者之后执行代码,就可以使用attribute。
#include <stdio.h>
#include <stdlib.h>
__attribute__((constructor))
void before(void)
{
printf("this is before ...\n");
}
__attribute__((destructor))
void after(void)
{
printf("this is after ...\n");
}
int main()
{
printf("hellowrold\n");
return 0;
}
定义两个普通函数,一个before,一个after,分别在函数的上面加上attribute修饰,attribute前后各有两个下划线,括号也是两个叠加在一起,参数一个是constructor,一个是destructor,翻译过来有点像C++里面的构造函数和析构函数。
编译运行程序,即使before和after没有被调用,也仍然会被执行。
root@Turbo:test# gcc test.c -o test
root@Turbo:test# ./test
this is before ...
hellowrold
this is after ...
root@Turbo:test#
当然,attribute语法没有那么严格,即使和函数放在同一行,也可以编通过。
void __attribute__((constructor)) before(void)
{
printf("this is before ...\n");
}
void __attribute__((destructor)) after(void)
{
printf("this is after ...\n");
}
attribute后面的参数有很多,我们随便挑几个看下。
比如noreturn,意思就是没有返回值的意思。
随便来个函数,返回值是void,如果加上noreturn属性,编译的时候就会提示警告,因为void也属于返回值。
#include <stdio.h>
#include <stdlib.h>
__attribute__((noreturn))
void test()
{
}
int main()
{
return 0;
}
root@Turbo:test# gcc test.c -o test
test.c: In function ‘test’:
test.c:8:1: warning: ‘noreturn’ function does return
8 | }
| ^
root@Turbo:test#
所以必须在函数内部调用同样具有noreturn属性的函数,编译才能通过。
__attribute__((noreturn))
void test()
{
exit(0);
}
再比如参数mode,用来设置整型的长度,可以是QI,一个字节,可以是HI,两个字节。
typedef unsigned int myint __attribute__((mode(QI)));
最常见的参数应该是packed,一般用于结构体后面。
正常的结构体会有字节对齐,比如这样的:
struct Test
{
char ch;
int id;
char sex;
int age;
};
在内存在中占了16个字节。
加上packed属性,就会丢掉字节对齐,该多少个字节就是多少个字节。
#include <stdio.h>
#include <stdlib.h>
struct Test
{
char ch;
int id;
char sex;
int age;
}__attribute__((packed));
int main()
{
printf("%lu\n", sizeof(struct Test));
return 0;
}
root@Turbo:test# ./test
10
root@Turbo:test#
当然,packed还可以换成aligned,就是指定对齐宽度。
struct Test
{
char ch;
int id;
char sex;
int age;
}__attribute__((aligned(32)));
最后,再看一个unused,如果你在代码中定义了静态函数但是没有调用,编译的时候编译器就会提示警告,加上unused,就能消除这个警告。
#include <stdio.h>
#include <stdlib.h>
__attribute__((unused))
static void test()
{
}
int main()
{
return 0;
}