GNU C 扩展之__attribute__ 机制简介
C语言GNU扩展语法
GNU C 9条扩展语法GNC CC是一个功能非常强大的跨平台C编译器,它对标准C语言进行了一系列扩展,以增强标准C的功能,这些扩展对优化、目标代码布局、更安全的检查等方面提供了很强的支持。
本文把支持GNU扩展的C语言称为GNU C。
Linux内核代码使用了大量的GNU C扩展,以至于能够编译Linux内核的唯一编译器是GNU CC,以前甚至出现过编译Linux内核要使用特殊的GNU CC版本的情况。
本文是对Linux内核使用的GNU C扩展的一个汇总,希望当你读内核源码遇到不理解的语法和语义时,能从本文找到一个初步的解答,更详细的信息可以查看。
文中的例子取自Linux 2.4.18。
1、零长度和变量长度数组组长度为1,分配时计算对象大小比较复杂。
3、语句表达式GNU C把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方,你可以在语句表达式中使用循环、局部变量等,原本只能在复合语句中使用。
例如:复合语句的最后一个语句应该是一个表达式,它的值将成为这个语句表达式的值。
这个定义计算x和y分别两次,当参数有副作用时,将产生不正确的结果,使用语句表达式只计算参数一次,避免了可能的错误。
语句表达式通常用于宏定义。
4、typeof 关键字使用前一节定义的宏需要知道参数的类型,利用typeof可以定义更通用的宏,不必事先这里typeof(x)表示x的值类型,第3行定义了一个与x 类型相同的局部变量_x 并初使化为x,注意第5行的作用是检查参数x和y的类型是否相同。
typeof 可以用在任何类型可以使用的地方,通常用于宏定义。
5、可变参数宏这里arg表示其余的参数,可以是零个或多个,这些参数以及参数之间的逗号构成arg 的值,在宏扩展时替换arg,例如:使用##的原因是处理arg不匹配任何参数的情况,这时arg的值为空,GNU C预处理器在这种特殊情况下,丢弃##之前的逗号,这样扩展为注意最后没有逗号。
__attribute__用法
__attribute__用法__attribute__是GCC编译器提供的一种语法扩展,用于指定变量、函数、结构体等的属性。
通过__attribute__可以告诉编译器一些额外的信息,从而优化代码或生成更好的代码。
下面是一些常用的__attribute__用法:1. __attribute__((packed))这个属性告诉编译器取消结构体中成员之间的内存对齐,使得结构体的大小最小。
这个属性通常用于网络编程中,将数据封装成二进制流传输时可以减小数据的大小。
示例代码:struct __attribute__((packed)) Person {char name[20];int age;};2. __attribute__((noreturn))这个属性用于告诉编译器函数不会返回,比如exit函数和abort 函数。
这样编译器就可以在函数调用点后面省略一些代码,以提高程序运行效率。
示例代码:void __attribute__((noreturn)) my_exit(int status) {// 执行一些清理工作exit(status);}3. __attribute__((aligned(n)))这个属性告诉编译器变量需要按照n字节对齐。
n必须是2的幂,通常是2、4、8或16字节。
这个属性可以用于优化内存访问的效率,但是会增加内存的消耗。
示例代码:int __attribute__((aligned(16))) a[4];4. __attribute__((section('name')))这个属性用于将变量或函数放到指定的段(section)中。
段是一种内存区域,程序在运行时可以根据需要将段加载到内存中。
这个属性通常用于嵌入式系统的开发,可以将一些特定的代码和数据放到特定的段中,以便于管理和使用。
示例代码:int __attribute__((section('mysect'))) b;5. __attribute__((weak))这个属性用于将函数或变量声明为弱符号。
attribute用法 c语言
attribute用法 c语言C语言是一种广泛使用的高级编程语言,被广泛用于操作系统、嵌入式系统和底层开发等领域。
在C语言中,attribute是一个重要的概念,用于为程序或者变量提供额外的信息或者指示。
本文将详细介绍attribute在C语言中的使用方法,通过举例说明,帮助读者更好地理解和应用。
一、attribute简介attribute是一个与变量、函数或结构体等相关的修饰符,它可以用来提供编译器特定的指示或额外的信息。
大多数C编译器都支持attribute,并且每个编译器都可能会有一些自己的特定attribute。
在C语言中,attribute通常以两个双下划线(__)开头。
二、attribute的常见用法1. `__attribute__((packed))`这个attribute可用于结构体的定义中,它会告诉编译器对该结构体进行紧凑排列,即不添加任何字节的填充,从而减小结构体的内存占用。
举个例子,假设我们有一个结构体Student:struct Student {char name[20];int age;} __attribute__((packed));在上述例子中,使用了`__attribute__((packed))`,结构体内的成员将会按照紧凑的方式存储,不会有任何填充字节。
2. `__attribute__((unused))`这个attribute可用于函数或变量的定义中,它会告诉编译器该函数或变量可能在代码中未使用,从而避免编译器产生未使用变量的警告。
void func() __attribute__((unused));上述例子中的函数`func`被添加了`__attribute__((unused))`,编译器将不会对该函数产生未使用函数的警告。
3. `__attribute__((deprecated))`这个attribute可用于函数或变量的定义中,它会告诉编译器该函数或变量已经被废弃,不推荐使用。
__attribute__详解及应用
__attribute__详解及应⽤之前做过App的启动优化,遇到了+load优化的问题,后来想⼀想除了initializers代替+load还有没有什么好的⽅法,然后就搜到了运⽤编译属性__attribute__优化,于是查找了很多⽂章,系统的整理了下__attribute__。
本⽂⼤部分内容来⾃引⽤的⽂章,如果想看更多更详细内容可以查看引⽤⽂章。
__attribute__ 介绍__attribute__是⼀个编译属性,⽤于向编译器描述特殊的标识、错误检查或⾼级优化。
它是GNU C特⾊之⼀,系统中有许多地⽅使⽤到。
__attribute__可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute)等。
__attribute__ 格式12__attribute__ ((attribute-list))__attribute__ 常⽤的编译属性及简单应⽤format这个属性指定⼀个函数⽐如printf,scanf作为参数,这使编译器能够根据代码中提供的参数检查格式字符串。
对于追踪难以发现的错误⾮常有帮助。
format参数的使⽤如下:1format (archetype, string-index, first-to-check)第⼀参数需要传递archetype指定是哪种风格,这⾥是 NSString;string-index指定传⼊函数的第⼏个参数是格式化字符串;first-to-check指定第⼀个可变参数所在的索引.C中的使⽤⽅法12extern int my_printf (void *my_object, const char *my_format, ...) __attribute__((format(printf, 2, 3)));在Objective-C 中通过使⽤__NSString__格式达到同样的效果,就像在NSString +stringWithFormat:和NSLog()⾥使⽤字符串格式⼀样1 2 3FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); + (instancetype)stringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);__attribute__((constructor))确保此函数在在main函数被调⽤之前调⽤,iOS中在+load之后main之前执⾏。
__attribute__用法
C语言中的__attribute__机制
C语言中的__attribute__机制分类:C/C++2011-10-24 19:53100人阅读评论(0)收藏举报c语言attributesprofiling编译器structGNU C的一大特色(却不被初学者所知)就是__attribute__机制。
__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
__attribute__书写特征是:__attribute__前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数。
__attribute__语法格式为:__attribute__ ((attribute-list))其位置约束为:放于声明的尾部“;”之前。
函数属性(Function Attribute)函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。
__attribute__机制也很容易同非GNU应用程序做到兼容之功效。
GNU CC需要使用–Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。
下面介绍几个常见的属性参数。
__attribute__ format该__attribute__属性可以给被声明的函数加上类似printf或者scanf的特征,它可以使编译器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。
该功能十分有用,尤其是处理一些很难发现的bug。
format的语法格式为:format (archetype, string-index, first-to-check)format属性告诉编译器,按照printf, scanf,strftime或strfmon的参数表格式规则对该函数的参数进行检查。
“archetype”指定是哪种风格;“string-index”指定传入函数的第几个参数是格式化字符串;“first-to-check”指定从函数的第几个参数开始按上述规则进行检查。
一套完全自由的操作系统都有这个秘密
一套完全自由的操作系统都有这个秘密GNU计划,又称革奴计划,是由Richard Stallman在1983年9月27日公开发起的。
它的目标是创建一套完全自由的操作系统,它在编写Linux的时候自己制作了一个标准成为GNU C标准,但是作为GNU C一大特色的__attribute__机制却为许多人所不知,现在让我们一起走进__attribute__的世界,来揭开它的神秘面纱。
对于GNU C的__attribute__机制,它有什么神奇的作用呢?你们是不是已经迫不及待了,对于__attribute__它可以修饰变量属性和函数属性,它的语法格式为:“__attribute__((参数));”,下面我们慢慢道来。
当我们初次学习一门语言的时候,都会写一个很经典的程序,没错就是在屏幕上输出Hello world,现在对我们来说写一段hello world程序,都是顺手捏来的事了,那么你看过这样的Hello world吗?#include#include__attribute__((constructor())) void pre_proc_1(void){printf("\nhello world\n");}__attribute__((destructor())) void end_proc_1(void){printf("\nHello World\n",__LINE__);}int main(int args,char **argv){return 0;}可以猜到程序输出什么结果吗?没错也是输出Hello world,直到为什么这样吗?细心的人肯定看到了在两个子函数前面使用了__attribute__((constructor()))和__attribute__((destructor))来修饰子函数,那么它们的作用是什么意思呢?被。
gcc的编译属性和选项
gcc的编译属性和选项1.指定内存默认对其参数:__attribute__((packed)):按⼀字节对其__attribute__((aligned(n))):从此之后默认按n字节对其例如:struct stu{ int a; char b;}__attribute__((packed));struct stu{ int a __attribute__((aligned(16))); char b;};例⼦#include <stdio.h>struct ss{char a __attribute__((aligned(16)));int b;//① __attribute__((aligned(16)));};//②__attribute__((aligned(16)));void main(){int i;printf("%d\n", sizeof(struct ss));struct ss s1 = {0x11, 0x55443322};unsigned char *p = (unsigned char *)&s1;for(i=0; i<sizeof(s1); i++){printf("0x%x\n", *(p+i));}}输出:160x110xd10x980x00x220x330x440x550xe00xfc0x980x00xf40xef0x980x0可以看出:__attribute__((aligned(16)))在哪个域后⾯修饰哪个域(注意仅对此域有效,对其它域⽆效),更改了这个域的实际对齐参数,实际对齐参数决定了此域的起始存储位置,再结合结构体的总⼤⼩必须能整除每⼀个域的最⼤对齐参数,因此可以推出来结构体的⼤⼩和内存的存储关系。
将结构体中注释掉掉的部分加上结构体⼤⼩就是32字节。
若只要③处,设定的只是结构体间对齐,结构体成员的存储顺序不变,只是结构体变长了。
__attribute__()用法
__attribute__()用法一、概述在编程中,我们常常会使用各种修饰符来改变代码的行为。
而在C语言中,使用`__at tri b ut e__()`函数,我们可以更加灵活地对函数、变量、类型等进行修饰,以达到特定的目的。
本文将介绍`__a tt ri bu te__()`的基本语法和常见用法。
二、基本语法`__a tt ri bu te__()`函数的基本语法如下:__at tr ib ut e__((at t ri bu te-l is t))其中,`at tr ib ut e-l is t`是一个由多个属性参数构成的逗号分隔列表。
每个属性参数使用双下划线`__`包围,属性参数的取值可以是一个或多个,用于指定相应的修饰符。
三、常见用法1.函数属性1.1优化级别通过`__a tt ri bu te__`函数,我们可以指定函数的优化级别,让编译器对函数进行特定的优化处理。
例如:v o id__at tr ib ut e__((o pt im iz e("O2")))m yF un ct io n(){//函数体}在上述示例中,我们指定了函数`my Fu nct i on()`的优化级别为O2,表示使用较高的优化级别对其进行编译。
1.2内联函数使用`__a tt ri bu te__`函数,我们可以将函数声明为内联函数,以提高函数调用的效率。
例如:i n li ne vo id__at tri b ut e__((a lw ay s_i n li ne))my Fu nc tio n(){//函数体}上述代码中,我们将函数`m yF un ct io n()`声明为内联函数,并使用`a lw ay s_in li ne`属性参数,确保该函数总是内联展开。
2.变量属性2.1对齐方式使用`__a tt ri bu te__`函数,我们可以指定变量的对齐方式,以满足特定的内存对齐需求。
__attribute__详解
__attribute__详解GNU C的一大特色就是__attribute__机制。
__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
__attribute__书写特征是:__attribute__前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数。
__attribute__语法格式为:__attribute__ ((attribute-list))其位置约束为:放于声明的尾部“;”之前。
函数属性(Function Attribute)函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。
__attribute__机制也很容易同非GNU应用程序做到兼容之功效。
GNU CC需要使用–Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。
下面介绍几个常见的属性参数。
1.__attribute__ format该__attribute__属性可以给被声明的函数加上类似printf或者scanf的特征,它可以使编译器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。
该功能十分有用,尤其是处理一些很难发现的bug。
format的语法格式为:format (archetype, string-index, first-to-check)format 属性告诉编译器,按照printf, scanf, strftime或strfmon的参数表格式规则对该函数的参数进行检查。
“archetype”指定是哪种风格;“string-index”指定传入函数的第几个参数是格式化字符串;“first-to-check”指定从函数的第几个参数开始按上述规则进行检查。
具体使用格式如下:__attribute__((format(printf,m,n)))__attribute__((format(scanf,m,n)))其中参数m与n的含义为:m:第几个参数为格式化字符串(format string);n:参数集合中的第一个,即参数“…”里的第一个参数在函数参数总数排在第几,注意,有时函数参数里还有“隐身”的呢,后面会提到;在使用上,__attribute__((format(printf,m,n)))是常用的,而另一种却很少见到。
C++__attribute__((weak)) 简介及作用
__attribute__((weak)) 简介及作用场景:A,B两个模块,A模块调用了不确定B模块是否提供了函数,但是又不得不调用,这个时候在A模块中再申明一个弱符号函数,即用weak,如果外部提供了调用外部的,如果没提供调用申明的。
弱符号:若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak属性,则这些全局符号不会引发重定义错误。
链接器会忽略弱符号,去使用普通的全局符号来解析所有对这些符号的引用,但当普通的全局符号不可用时,链接器会使用弱符号。
当有函数或变量名可能被用户覆盖时,该函数或变量名可以声明为一个弱符号。
示例://模块A中调用func,但是不确定外部是否提供了该函数extern int func(void);int a = func();如果直接这么调用,如果外部不提供该函数程序可能出现crash。
所以在本模块中__attribute__((weak))就派上了用场int __attribute__((weak)) func(......){return 0;}这样的话如果模块B提供了func就调用模块B的,如果没提供就调用本模块在中weak声明的。
__attribute__((unused)) 的含义在C程序中,如果定义了一个静态函数,而没有去使用,编译时会有一个告警:#include<stdio.h>int main(void){printf("main\n");}static void a(void){printf("a\n");}$ gcc a.c -Walla.c:8:13: warning: 'a' defined but not used [-Wunused-function]static void a(void)^而使用attribute((unused))可以告诉编译器忽略此告警:#include<stdio.h>int main(void){printf("main\n");}__attribute__((unused)) static void a(void){printf("a\n");}$ gcc a.c -Wall$noinline & always_inline内联函数:内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。
__attribute__机制
__attribute__机制xdata uchar dat_tm1818[18][16] _at_ 0x0e00; //成功过__align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)))__align(32):32位对齐__attribute__ :增加变量属性((at(0X68000000))) :变量在存储器中的绝对地址是0X680000001. __attribute__GNU C的一大特色(却不被初学者所知)就是__attribute__机制。
__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)__attribute__前后都有两个下划线,并且后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数__attribute__语法格式为:__attribute__ ( ( attribute-list ) )函数属性(Function Attribute),函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。
__attribute__机制也很容易同非GNU应用程序做到兼容。
GNU CC需要使用–Wall,这是控制警告信息的一个很好的方式。
下面介绍几个常见的属性参数。
2. format该属性可以使编译器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。
它可以给被声明的函数加上类似printf或者scanf的特征,该功能十分有用,尤其是处理一些很难发现的bug。
format的语法格式为:format ( archetype, string-index, first-to-check )format属性告诉编译器,按照printf,scanf,strftime或strfmon的参数表格式规则对该函数的参数进行检查。
c语言attribute用法
c语言attribute用法
摘要:
1.C 语言attribute 概述
2.attribute 的应用场景
3.attribute 的基本语法
4.attribute 的实例分析
正文:
【C 语言attribute 概述】
C 语言attribute 是一种用于修饰结构体、联合体和变量的关键字,它可以为这些数据类型添加额外的信息,如访问权限、存储位置等。
attribute 在C 语言中并不是标准关键字,而是GNU C 扩展库的一部分,因此并非所有编译器都支持它。
然而,许多现代编译器都支持attribute,如GCC 和Clang。
【attribute 的应用场景】
attribute 主要用于以下场景:
1.声明变量为全局或局部静态
2.指定变量的初始化方式
3.限制变量的访问权限
4.指定结构体或联合体的对齐方式
5.为函数参数或返回值指定类型
【attribute 的基本语法】
attribute 的基本语法如下:
```
attribute(attribute-specifier)
```
其中,`attribute-specifier`可以是一个或多个关键字,用空格分隔。
你知道GNUC对C语言的扩展吗?
你知道GNUC对C语言的扩展吗?为了方便使用,GNU C在标准C语言的基础上进行了部分方便开发的扩展。
这里讲解一些开发中可能会用到的,或者使用频率比较高的内容。
零长度数组和变量长度数组GNU C 允许使用零长度数组,比如:char data[0];GNU C 允许使用一个变量定义数组的长度如:int n=0;scanf('%d',&n);int array[n];case 范围GNU C支持 case x...y这样的语法,[x,y]之间数均满足条件。
case 'a'...'z': /*from 'a' to 'z'*/break;语句表达式GNU C 把包含在括号中的复合语句看作是一个表达式,称为语句表达式。
#define min_t(type,x,y)\({type __x=(x); type __y=(y);__x<__y?__x:__y;})这种写法可以避免#define min_t(x,y) ((x)<(y)?(x):(y))在min_t(x++,++y)中出现的副作用typeof 关键字typeof(x)可以获得x的类型借助typeof关键字我们可以重新定义min_t:#define min_t(x,y)\({typeof(x) __x=(x); typeof(y) __y=(y);__x<__y?__x:__y;})可变参数宏GNU C中宏也支持可变参数#define pr_debug(fmt,arg...) \printk(fmt,##arg)这里,如果可变参数被忽略或为空,“##”操作将使预处理器去掉它前面的那个逗号。
如果你在宏调用时,确实提供了一些可变参数,GNU C也会工作正常,它会把这些可变参数放到逗号的后面。
标号元素标准C要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C中,通过指定索引或结构体成员名,允许初始化以任意顺序出现。
__attribute__机制详解
__attribute__机制详解__attribute 语法的来源GNU C 的⼀⼤特⾊就是__attribute__ 机制。
attribute 可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
其位置约束为:放于声明的尾部“;” 之前attribute 书写特征为: attribute 前后都有两个下划线,并切后⾯会紧跟⼀对原括弧,括弧⾥⾯是相应的__attribute__ 参数。
attribute 语法格式为: attribute ((attribute-list))当__attribute__ ⽤于修饰对象时,它就如同C 语⾔语法体系结构的类型限定符,跟const , volatile , restrict 等属⼀类。
当__attribute__ ⽤于修饰函数时,它就相当于⼀个函数说明符,跟inline,Noreturn 属同⼀类。
当__attribute_ ⽤于修饰⼀个结构体,联合体或者枚举类型,该限定符只能放在类型标识符之前。
__attribute 所⽀持的类型当我们需要识别当前编译器能否⽀持GNU 语法拓展,我们可以使⽤ __GNU __ 宏作为区分函数属性(Function Attribute)类型属性(Type Attributes)变量属性(Variable Attribute)Clang特有的noreturn aligned alias availabilitynoinline packed at(address) overloadablealways_inline bitband alignedflatten deprecatedpure noinlineconst packedconstructor weakdestructor weakref(“target”)sentinel section(“name”)format unusedformat_arg usedsection visibility(“visibility_type”)used zero_initunuseddeprecatedweakmallocaliaswarn_unused_resultnonnullnothrow (不抛出C++ 异常)常⽤函数属性attribute((Noreturn)) function attribute表⽰没有返回值这个属性告诉编译器函数不会返回,这可以⽤来抑制关于未达到代码路径的错误。
__attribute__((__packed__))
__attribute__((__packed__))⾸先,解释下 “__attribute__ ((__packed__))” 是做什么的?我们知道,通常定义⼀个U32 ,CPU 期望这个 U32 地址是 DW 对齐的, 这样对CPU访问 mem bus ⽐较友好。
所以,当我们定义这样⼀个结构体:struct test{char i,uint32 a}那么,编译器会默认在 i 和 a 之间插⼊ reserve,确保 a 的位置是 4 对齐的。
sizeof(test) = 8.它就等效于:struct test{char i,char reserve[3],uint32 a}加⼊ “__attribute__ ((__packed__))” 的效果,则在于避免编译器 “⾃作聪明”。
告诉编译器,我们这⾥不需要补全。
struct __attribute__ ((__packed__)) test{char i,uint32 a}sizeof(test) = 5; 这会造成 a 地址不对齐,反⽽引⼊⿇烦。
那为什么要有这个东西呢?如下截图,是SPDK⾥⾯关于 SGL 的定义。
我想这个最⼤的好处就是:严格按照(NVMe) SPEC 定义数据结构,避免编译器优化。
也就是说,static 类型的,系统优化会造成通讯或者使⽤错误的,就要加这个类型。
如果只是软件⾃⽤的变量,那最好就不⽤加了,避免出现不对齐的地址,导致性能降低————————————————版权声明:本⽂为CSDN博主「褚道长」的原创⽂章,遵循CC 4.0 BY-SA版权协议,转载请附上原⽂出处链接及本声明。
原⽂链接:https:///zuiyinian/article/details/81174031。
GNU CC中的attribute
GNU CC中的attributeGNU C的一大特色就是__attribute__机制。
GNU C扩展的__attribute__ 机制被用来设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
__attribute__书写特征是:__attribute__前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数。
__attribute__语法格式为:__attribute__ ((attribute-list))其位置约束为:放于声明的尾部―;‖之前。
一.函数属性(Function Attribute)函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。
__attribute__机制也很容易同非GN U应用程序做到兼容之功效。
GNU CC需要使用–Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。
下面介绍几个常见的属性参数。
__attribute__ format该__attribute__属性表示函数使用printf, scanf 或strftime 风格的参数,使用这类函数最容易犯的错误是格式串与参数不匹配,指定format 属性可以让编译器根据格式串检查参数类型。
该功能十分有用,尤其是处理一些很难发现的bug。
format的语法格式为:format (archetype, string-index, first-to-check)format属性告诉编译器,按照printf, scanf,strftime或strfmon的参数表格式规则对该函数的参数进行检查。
―archetype‖指定是哪种风格;―string-index‖指定传入函数的第几个参数是格式化字符串;―first-to-check‖指定从函数的第几个参数开始按上述规则进行检查。
C语言中的attribute机制
分类:人阅读评论()收藏举报语言编译器地一大特色(却不被初学者所知)就是机制.可以设置函数属性()、变量属性()和类型属性().书写特征是:前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应地参数.语法格式为:(())其位置约束为:放于声明地尾部“;”之前.函数属性()函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面地功能更强大.机制也很容易同非应用程序做到兼容之功效.需要使用–编译器来击活该功能,这是控制警告信息地一个很好地方式.下面介绍几个常见地属性参数.该属性可以给被声明地函数加上类似或者地特征,它可以使编译器检查函数声明和函数实际调用参数之间地格式化字符串是否匹配.该功能十分有用,尤其是处理一些很难发现地.地语法格式为:(, , )属性告诉编译器,按照, ,或地参数表格式规则对该函数地参数进行检查.“”指定是哪种风格;“”指定传入函数地第几个参数是格式化字符串;“”指定从函数地第几个参数开始按上述规则进行检查.具体使用格式如下:((()))((()))其中参数与地含义为::第几个参数为格式化字符串();:参数集合中地第一个,即参数“…”里地第一个参数在函数参数总数排在第几,注意,有时函数参数里还有“隐身”地呢,后面会提到;在使用上,((()))是常用地,而另一种却很少见到.下面举例说明,其中为自己定义地一个带有可变参数地函数,其功能类似于:;( *,...) ((()));;( ,*,...)((()));需要特别注意地是,如果是一个函数地成员函数,那么和地值可有点“悬乎”了,例如:;( ,*,...)((()));其原因是,类成员函数地第一个参数实际上一个“隐身”地“”指针.(有点基础地都知道点指针,不知道你在这里还知道吗?)这里给出测试用例:,代码如下:::( *,...)((()));::():{:("\");:("\");:("\","");:("\");:}运行$ ––后,输出结果为:: `':: : ( ): : ( ): : 如果在中地函数声明去掉((())),再重新编译,既运行$ ––后,则并不会输出任何警告信息.注意,默认情况下,编译器是能识别类似地“标准”库函数.该属性通知编译器函数从不返回值,当遇到类似函数需要返回值而却不可能运行到返回值处就已经退出来地情况,该属性可以避免出现错误信息.库函数中地()和()地声明格式就采用了这种格式,如下所示:() (()) () (()); 为了方便理解,大家可以参考如下地例子:: ;测试(())();( ){( > ){();* 程序不可能到达这里*};}编译显示地输出信息为:$ ––: `':: : 警告信息也很好理解,因为你定义了一个有返回值地函数却有可能没有返回值,程序当然不知道怎么办了!加上(())则可以很好地处理类似这种问题.把();修改为:() (());之后,编译不会再出现警告信息.该属性只能用于带有数值类型参数地函数上.当重复调用带有数值参数地函数时,由于返回值是相同地,所以此时编译器可以进行优化处理,除第一次需要运算外,其它只需要返回第一次地结果就可以了,进而可以提高效率.该属性主要适用于没有静态状态()和副作用地一些函数,并且返回值仅仅依赖输入地参数.为了说明问题,下面举个非常“糟糕”地例子,该例子将重复调用一个带有相同参数值地函数,具体如下:( ) (());...( ; { () ;} } 通过添加(())声明,编译器只调用了函数一次,以后只是直接得到了相同地一个返回值.事实上,参数不能用在带有指针类型参数地函数中,因为该属性不但影响函数地参数值,同样也影响到了参数指向地数据,它可能会对代码本身产生严重甚至是不可恢复地严重后果.并且,带有该属性地函数不能有任何副作用或者是静态地状态,所以,类似()或()地函数是不适合使用该属性地.该参数可以使程序在编译时,在函数地入口和出口处生成调用.恰好在函数入口之后并恰好在函数出口之前,将使用当前函数地地址和调用地址来调用下面地函数.(在一些平台上,不能在超过当前函数范围之外正常工作,所以调用地址信息可能对函数是无效地.)( *, *);( *, *);其中,第一个参数是当前函数地起始地址,可在符号表中找到;第二个参数是指调用处地址.也可用于在其它函数中展开地内联函数.从概念上来说,调用将指出在哪里进入和退出内联函数.这就意味着这种函数必须具有可寻址形式.如果函数包含内联,而所有使用到该函数地程序都要把该内联展开,这会额外地增加代码长度.如果要在代码中使用声明,必须提供这种函数地可寻址形式.可对函数指定属性,在这种情况下不会进行操作.例如,可以在以下情况下使用属性:上面列出地函数、高优先级地中断例程以及任何不能保证正常调用地函数.如果使用了,将在绝大多数用户编译地函数地入口和出口点调用函数.使用该属性,将不进行操作.若函数被设定为属性,则该函数会在()函数执行之前被自动地执行.类似地,若函数被设定为属性,则该函数会在()函数执行之后或者()被调用后被自动地执行.拥有此类属性地函数经常隐式地用在程序地初始化数据方面.这两个属性还没有在面向对象中实现.同时使用多个属性可以在同一个函数声明里使用多个,并且实际应用中这种情况是十分常见地.使用方式上,你可以选择两个单独地,或者把它们写在一起,可以参考下面地例子:* 把类似地消息传递给并退出*( *, ...) (()) (((, , )));或者写成( *, ...) ((, (, , )));如果带有该属性地自定义函数追加到库地头文件里,那么所以调用该函数地程序都要做相应地检查.和非编译器地兼容性庆幸地是,设计地非常巧妙,很容易作到和其它编译器保持兼容,也就是说,如果工作在其它地非编译器上,可以很容易地忽略该属性.即使使用了多个参数,也可以很容易地使用一对圆括弧进行处理,例如:* 如果使用地是非, 那么就忽略*() **需要说明地是,适用于函数地声明而不是函数地定义.所以,当需要使用该属性地函数时,必须在同一个文件里进行声明,例如:* 函数声明*( *, ...) (()) ((()));( *, ...){* 函数定义*} 更多地属性含义参考:变量属性()关键字也可以对变量()或结构体成员()进行属性设置.这里给出几个常用地参数地解释,更多地参数可参考本文给出地连接.在使用参数时,你也可以在参数地前后都加上“”(两个下划线),例如,使用而不是,这样,你就可以在相应地头文件里使用它而不用关心头文件里是否有重名地宏定义. ()该属性规定变量或结构体成员地最小地对齐格式,以字节为单位.例如:(( ())) ; 编译器将以字节(注意是字节不是位)对齐地方式分配一个变量.也可以对结构体成员变量设置该属性,例如,创建一个双字对齐地对,可以这么写:{ [] (( ())); }; 如上所述,你可以手动指定对齐地格式,同样,你也可以使用默认地对齐方式.如果后面不紧跟一个指定地数字值,那么编译器将依据你地目标机器情况使用最大最有益地对齐方式.例如:[] (()); 选择针对目标机器最大地对齐方式,可以提高拷贝操作地效率.属性使被设置地对象占用更多地空间,相反地,使用可以减小对象占用地空间.需要注意地是,属性地效力与你地连接器也有关,如果你地连接器最大只支持字节对齐,那么你此时定义字节对齐也是无济于事地.使用该属性可以使得变量或者结构体成员使用最小地对齐方式,即对变量是一字节对齐,对域()是位对齐.下面地例子中,成员变量使用了该属性,则其值将紧放置在地后面:{ ;[] (());}; 其它可选地属性值还可以是:,,,,,,,,,,,,,等,详细信息可参考:类型属性()关键字也可以对结构体()或共用体()进行属性设置.大致有六个参数值可以被设定,即:,, , , 和 .在使用参数时,你也可以在参数地前后都加上“”(两个下划线),例如,使用而不是,这样,你就可以在相应地头文件里使用它而不用关心头文件里是否有重名地宏定义. ()该属性设定一个指定大小地对齐格式(以字节为单位),例如:{ []; } (( ()));(( ()));该声明将强制编译器确保(尽它所能)变量类型为或者地变量在分配空间时采用字节对齐方式.如上所述,你可以手动指定对齐地格式,同样,你也可以使用默认地对齐方式.如果后面不紧跟一个指定地数字值,那么编译器将依据你地目标机器情况使用最大最有益地对齐方式.例如:{ []; } (());这里,如果()地大小为(),那么,地大小就为.取一个地次方值,使得该值大于等于,则该值为,所以编译器将设置类型地对齐方式为字节.属性使被设置地对象占用更多地空间,相反地,使用可以减小对象占用地空间.需要注意地是,属性地效力与你地连接器也有关,如果你地连接器最大只支持字节对齐,那么你此时定义字节对齐也是无济于事地.使用该属性对或者类型进行定义,设定其类型地每一个变量地内存约束.当用在类型定义时,暗示了应该使用最小完整地类型().下面地例子中,类型地变量数组中地值将会紧紧地靠在一起,但内部地成员变量不会被“”,如果希望内部地成员变量也被地话,也需要使用进行相应地约束.{;;};{;;;} (());其它属性地含义见:变量属性与类型属性举例下面地例子中使用属性定义了一些结构体及其变量,并给出了输出结果和对结果地分析.程序代码为:{;;;}((())) ;{;;;;}((())) ;(){("()()()\"()()());(" \", ()());;}输出结果:()()()分析:():() () ()下面是一些便捷地连接:;;;;;;;:.有关地相对简单地介绍:.详细介绍:本文来自博客,如果查看原文请点:。
__attribute__用法
__attribute__用法在C语言中,__attribute__是一种特殊的语法,用于给函数、变量、结构体等对象添加属性。
它可以用于告诉编译器一些额外的信息,帮助编译器进行优化或者进行静态检查。
在本文中,我们将对__attribute__的使用方法进行详细解析,并介绍一些常用的属性。
1. __attribute__((packed))__attribute__((packed))可以用于结构体或者联合体,它告诉编译器不要对结构体进行字节对齐。
在默认情况下,编译器会对结构体进行字节对齐,以提高读写效率。
但是在一些特殊情况下,我们需要按照实际占用的字节数来定义结构体,这时就可以使用packed属性。
例如,我们定义一个结构体来表示一个位域:```struct BitField {unsigned int a : 1;unsigned int b : 2;unsigned int c : 3;} __attribute__((packed));```在上面的例子中,由于使用了packed属性,结构体BitField的大小将是6个字节,而不是按照默认的对齐方式4个字节。
2. __attribute__((aligned(n)))__attribute__((aligned(n)))可以用于变量或者结构体,它告诉编译器将对象对齐到n字节边界。
默认情况下,编译器会按照最大基本类型的大小进行对齐,例如int型变量会按照4字节对齐。
例如,我们定义一个变量,并要求将其对齐到8字节边界:```int var __attribute__((aligned(8)));```在上面的例子中,变量var将被对齐到8字节边界。
3. __attribute__((noreturn))__attribute__((noreturn))用于告诉编译器一个函数不会返回。
这对于一些特殊的函数非常有用,如exit函数、abort函数等。
C语言GNU扩展语法
GNU C 9条扩展语法GNC CC是一个功能非常强大的跨平台C编译器,它对标准C语言进行了一系列扩展,以增强标准C的功能,这些扩展对优化、目标代码布局、更安全的检查等方面提供了很强的支持。
本文把支持GNU扩展的C语言称为GNU C。
Linux内核代码使用了大量的GNU C扩展,以至于能够编译Linux内核的唯一编译器是GNU CC,以前甚至出现过编译Linux内核要使用特殊的GNU CC版本的情况。
本文是对Linux内核使用的GNU C扩展的一个汇总,希望当你读内核源码遇到不理解的语法和语义时,能从本文找到一个初步的解答,更详细的信息可以查看。
文中的例子取自Linux 2.4.18。
1、零长度和变量长度数组组长度为1,分配时计算对象大小比较复杂。
3、语句表达式GNU C把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方,你可以在语句表达式中使用循环、局部变量等,原本只能在复合语句中使用。
例如:复合语句的最后一个语句应该是一个表达式,它的值将成为这个语句表达式的值。
这个定义计算x和y分别两次,当参数有副作用时,将产生不正确的结果,使用语句表达式只计算参数一次,避免了可能的错误。
语句表达式通常用于宏定义。
4、typeof 关键字使用前一节定义的宏需要知道参数的类型,利用typeof可以定义更通用的宏,不必事先这里typeof(x)表示x的值类型,第3行定义了一个与x 类型相同的局部变量_x 并初使化为x,注意第5行的作用是检查参数x和y的类型是否相同。
typeof 可以用在任何类型可以使用的地方,通常用于宏定义。
5、可变参数宏这里arg表示其余的参数,可以是零个或多个,这些参数以及参数之间的逗号构成arg 的值,在宏扩展时替换arg,例如:使用##的原因是处理arg不匹配任何参数的情况,这时arg的值为空,GNU C预处理器在这种特殊情况下,丢弃##之前的逗号,这样扩展为注意最后没有逗号。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
extern void myprint(int l,const char format,...) __attribute__((format(printf,3,4)));
其原因是,类成员函数的第一个参数实际上一个“隐身”的“this”指针。(有点C++基础的都知道点this指针,不知道你在这里还知道吗?)
extern void myexit();
修改为:
extern void myexit() __attribute__((noreturn));
之后,编译不会再出现警告信息。
__attribute__ const
该属性只能用于带有数值类型参数的函数上。当重复调用带有数值参数的函数时,由于返回值是相同的,所以此时编译器可以进行优化处理,除第一次需要运算外,其它只需要返回第一次的结果就可以了,进而可以提高效率。该属性主要适用于没有静态状态(static state)和副作用的一些函数,并且返回值仅仅依赖输入的参数。
通过添加__attribute__((const))声明,编译器只调用了函数一次,以后只是直接得到了相同的一个返回值。
事实上,const参数不能用在带有指针类型参数的函数中,因为该属性不但影响函数的参数值,同样也影响到了参数指向的数据,它可能会对代码本身产生严重甚至是不可恢复的严重后果。
并且,带有该属性的函数不能有任何副作用或者是静态的状态,所以,类似getchar()或time()的函数是不适合使用该属性的。
7: myprint(i=%sn,6);
8: myprint(i=%sn,abc);
9: myprint(%s,%d,%dn,1,2);
10:}
运行$gcc –Wall –c attribute.c attribute后,输出结果为:
attribute.c In function `test'
为了说明问题,下面举个非常“糟糕”的例子,该例子将重复调用一个带有相同参数值的函数,具体如下:
extern int square(int n) __attribute__((const));... for (i = 0; i 100; i++ ) { total += square(5) + i; }
程序不可能到达这里
}
else
return 0;
}
编译显示的输出信息为:
$gcc –Wall –c noreturn.c
noreturn.c In function `test'
如果在attribute.c中的函数声明去掉__attribute__((format(printf,1,2))),再重新编译,既运行$gcc –Wall –c attribute.c attribute后,则并不会输出任何警告信息。
注意,默认情况下,编译器是能识别类似printf的“标准”库函数。
------------------------------------------------------------------------------------------------------
GNU C的一大特色(却不被初学者所知)就是__attribute__机制。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
在使用上,__attribute__((format(printf,m,n)))是常用的,而另一种却很少见到。下面举例说明,其中myprint为自己定义的一个带有可变参数的函数,其功能类似于printf:
m=1;n=2
extern void myprint(const char format,...) __attribute__((format(printf,1,2)));
这里给出测试用例:attribute.c,代码如下:
1:
2:extern void myprint(const char format,...) __attribute__((format(printf,1,2)));
3:
4:void test()
5:{
6: myprint(i=%dn,6);
声明:
此文为原创,欢迎转载,转载请保留如下信息 作者:聂(afreez) 北京-中关村
联系方式:afreez@ (欢迎与作者交流)
初次发布时间:2006-06-17
不经本人同意,不得用语商业或赢利性质目的,否则,作者有权追究相关责任!
attribute.c7 warning format argument is not a pointer (arg 2)
attribute.c9 warning format argument is not a pointer (arg 2)
attribute.c9 warning too few arguments for format
no_instrument_function
如果使用了-finstrument-functions ,将在绝大多数用户编译的函数的入口和出口点调用profiling函数。使用该属性,将不进行instrument操作。
constructordestructor
若函数被设定为constructor属性,则该函数会在main()函数执行之前被自动的执行。类似的,若函数被设定为destructor属性,则该函数会在main()函数执行之后或者exit()被调用后被自动的执行。拥有此类属性的函数经常隐式的用在程序的初始化数据方面。
函数属性(Function Attribute)
函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。__attribute__机制也很容易同非GNU应用程序做到兼容之功效。
GNU CC需要使用 –Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。下面介绍几个常见的属性参数。
m=2;n=3
extern void myprint(int l,const char format,...) __attribute__((format(printf,2,3)));
需要特别注意的是,如果myprint是一个函数的成员函数,那么m和n的值可有点“悬乎”了,例如:
m=3;n=4
__attribute__ format
该__attribute__属性可以给被声明的函数加上类似printf或者scanf的特征,它可以使编译器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。该功能十分有用,尤其是处理一些很难发现的bug。
format的语法格式为:
format (archetype, string-index, first-to-check)
name noreturn.c ;测试__attribute__((noreturn))
extern void myexit();
int test(int n)
{
if ( n 0 )
{
myexit();
具体使用格式如下:
__attribute__((format(printf,m,n)))
__attribute__((format(scanf,m,n)))
其中参数m与n的含义为:
m:第几个参数为格式化字符串(format string);
n:参数集合中的第一个,即参数“…”里的第一个参数在函数参数总数排在第几,注意,有时函数参数里还有“隐身”的呢,后面会提到;
instrumentation 也可用于在其它函数中展开的内联函数。从概念上来说,profiling调用将指出在哪里进入和退出内联函数。这就意味着这种函数必须具有可寻址形式。如果函数包含内联,而所有使用到该函数的程序都要把该内联展开,这会额外地增加代码长度。如果要在C 代码中使用extern inline声明,必须提供这种函数的可寻址形式。
-finstrument-functions
该参数可以使程序在编译时,在函数的入口和出口处生成instrumentation调用。恰好在函数入口之后并恰好在函数出口之前,将使用当前函数的地址和调用地址来调用下面的 profiling 函数。(在一些平台上,__builtin_return_address不能在超过当前函数范围之外正常工作,所以调用地址信息可能对profiling函数是无效的。)
可对函数指定no_instrument_function属性,在这种情况下不会进行instrumentation操作。例如,可以在以下情况下使用no_instrument_function属性:上面列出的profiling函数、高优先级的中断例程以及任何不能保证profiling正常调用的函数。
void __cyg_profile_func_enter(void this_fn, void call_site);
void __cyg_profile_func_exit(void this_fn, void call_site);
其中,第一个参数this_fn是当前函数的起始地址,可在符号表中找到;第二个参数call_site是指调用处地址。
format属性告诉编译器,按照printf, scanf, strftime或strfmon的参数表格式规则对该函数的参数进行检查。“archetype”指定是哪种风格;“string-index”指定传入函数的第几个参数是格式化字符串;“first-to-check”指定从函数的第几个参数开始按上述规则进行检查。
__attribute__书写特征是:__attribute__前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数。