美文网首页
__attribute__(编译属性)知识总结

__attribute__(编译属性)知识总结

作者: 晨晨晨序员 | 来源:发表于2018-08-27 01:00 被阅读0次

个人博客地址:iOS开发常用 __attribute__(编译属性)知识总结 - 王小熊他爸的博客

第0部分:说在前面的话

       使用Objective-C作为主要开发语言已经有一段时间了,其独特的语法相信也令初次接触她的人印象颇深。然而语法之外,当我们查看苹果提供的头文件,我还被另外一些符号所吸引,比如 “NS_DESIGNATED_INITIALIZER”、“API_AVAILABLE”等等。这些就是传说中的__attribute__(编译属性)。虽然从字面上很好理解其含义,也能猜到他们是一些与编译器相关的指令,但直到最近,我才终于搞清其背后的原理与历史。


这篇文章,就简单总结下 __attribute__的背后的一些编译器相关的知识与常见编译属性用法。

首先,引用一句比较正式的定义:

__attribute__is a compiler directive that specifies characteristics on declarations, which allows for more error checking and advanced optimizations.

实际上,__attribute__是GNU C 的特点之一,在这篇GNU的官方文档中有比较详细的介绍。

简单总结下:_attribute__有多种类型,Function-AttributesVariable-Attributes、Type-Attributes 、Label Attributes和 Enumerator Attributes。

书写特征是:__attribute__前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数。

语法格式为:__attribute__ ((attribute-list))

位置约束为:放于声明的尾部“;”之前。

而iOS目前的编译器llvm/Clang ,不仅对__attribute__提供了非常良好的支持,同时还增加了一些扩展,某些attribute甚至在iOS开发中起到了不可或缺的作用,下面就总结下在iOS开发中,比较常见和有趣的一些__attribute__用法:

第一部分:开发中比较常见的:

1、deprecated

在iOS中,常见的NS_DEPRECATED()宏实际就是__attribute__((deprecated)),还可以增加一些提示语变为__attribute__((deprecated(s)))。

2、availability

3、overloadable

Clang provides support for C++ function overloading in C. Function overloading in C is introduced using theoverloadableattribute. For example, one might provide several overloaded versions of atgsinfunction that invokes the appropriate standard function computing thesineof a value withfloat,double, orlong doubleprecision:

#include float__attribute__((overloadable))tgsin(floatx){returnsinf(x);}double__attribute__((overloadable))tgsin(doublex){returnsin(x);}longdouble__attribute__((overloadable))tgsin(longdoublex){returnsinl(x);}

4、format (gcc)

Theformatattribute specifies that a function takesprintf,scanf,strftimeorstrfmonstyle arguments which should be type-checked against a format string.

比如:

externintmy_printf(void*my_object,constchar*my_format,...)__attribute__((format(printf,2,3)));

5、nonnull (gcc)

extern void*my_memcpy(void*dest,constvoid*src,size_tlen)__attribute__((nonnull(1,2)));

iOS中对于nonnull使用不多,更为常见的是苹果在Xcode 6.3引入的一个Objective-C的新特性:nullability annotations

6、unused

This attribute, attached to a function, means that the function is meant to be possibly unused. GCC will not produce a warning for this function.

简而言之,可以用它来避免编译器产生unused警告。

7、unavailable 

用法:__attribute__((unavailable)),NS_UNAVAILABLE

这个挺实用,它的作用是告诉编译器该方法不可用,如果强行调用编译器会提示错误。比如某个类在构造的时候不想直接通过init来初始化,只能通过特定的初始化方法,就可以将init方法标记为unavailable。

其他常见的还有很多,不一一列举了,详见https://clang.llvm.org/docs/AttributeReference.html

第二部分:开发中不常使用,但恰当使用能起到事半功倍的效果:

1、__attribute__((objc_requires_super))

aka: NS_REQUIRES_SUPER,标志子类继承这个方法时需要调用 super,否则给出编译警告。

2、objc_subclassing_restricted

用来定义一个 Final Class

3、constructor / destructor

(该部分引用自https://blog.sunnyxx.com/2016/05/14/clang-attributes/)顾名思义,构造器和析构器,加上这两个属性的函数会在分别在可执行文件(或 shared library)load和 unload 时被调用,可以理解为在 main() 函数调用前和 return 后执行:

__attribute__((constructor))

static void beforeMain(void) {

NSLog(@"beforeMain");

}

__attribute__((destructor))

static void afterMain(void) {

NSLog(@"afterMain");

}

int main(int argc, const char * argv[]) {

NSLog(@"main");

return 0;

}

// Console:

// "beforeMain" -> "main" -> "afterMain"

constructor 和 +load 都是在 main 函数执行前调用,但 +load 比 constructor 更加早一些,因为 dyld(动态链接器,程序的最初起点)在加载 image(可以理解成 Mach-O 文件)时会先通知 objc runtime 去加载其中所有的类,每加载一个类时,它的 +load 随之调用,全部加载完成后,dyld 才会调用这个 image 中所有的 constructor 方法。

所以 constructor 是一个干坏事的绝佳时机:

所有 Class 都已经加载完成

main 函数还未执行

无需像 +load 还得挂载在一个 Class 中

PS:若有多个 constructor 且想控制优先级的话,可以写成 __attribute__((constructor(101))),里面的数字越小优先级越高,1 ~ 100 为系统保留。

4、objc_runtime_name

这个属性就非常有意思了,用于 @interface 或 @protocol,将类或协议的名字在编译时指定成另一个。

之前在项目中经常有一些需求需要修改类名,通过这个__attribute__只需一行代码就可以直接在完成了,awesome!但需要注意的是如果代码中有用反射就会出问题。或者做一些简单的类名混淆:

__attribute__((objc_runtime_name("abcdefghighlmn")))

@interface SecretClass : NSObject

@end

5、cleanup

作用:离开作用域之后执行指定的方法。实际应用中可以在作用域结束之后做一些特定的工作,比如清理。

Reactive Cocoa 用这个特性实现了神奇的 @onExit,关于这个 attribute,在sunnyxx的这篇博客中有非常详细的介绍。

6、objc_designated_initializer (NS_DESIGNATED_INITIALIZER)

aka:NS_DESIGNATED_INITIALIZER,这也是一个在iOS中非常常见的attribute,它可以指定类的初始化方法。指定初识化方法并不是对使用者。而是对内部的现实。

具体的讲解可以参见这篇文章:https://segmentfault.com/a/1190000004116196

这个attribute的目的其实是在初始化类的实例时,无论调用关系如何复杂,必须调用一次该类的Designated intializer(可以有多个),对于 Designated intializer,必须调用父类的Designated intializer。对于父类的父类这个规则亦然,对Designated intializer的调用一直要到根类。

7、objc_boxable

OC中常见的 @(10)这样的写法,它的实现方式就是利用该Function attributes:

struct __attribute__((objc_boxable)) some_struct {

int i;

};

union __attribute__((objc_boxable)) some_union {

int i;

float f;

};

typedef struct __attribute__((objc_boxable)) _some_struct some_struct;

some_struct ss;

NSValue *boxed = @(ss);

8、一些与内存管理相关的__attribute__

__attribute__((objc_precise_lifetime))

用这个attribute修饰一个变量,防止ARC过早释放它。即向编译器表明,变量在它所处的整个作用域内,都应被认为是有用的。

Foundation里提供了宏NS_VALID_UNTIL_END_OF_SCOPE。

__attribute__((objc_returns_inner_pointer))

用于修饰一个方法,防止ARC过早释放这个方法的所有者。Foundation里提供了宏NS_RETURNS_INNER_POINTER。

__attribute__((ns_returns_retained))

在Objective-C里,很多方法的命名都是有约定的含义的。比如以alloc、new、copy、mutableCopy开头的方法,会返回一个retain count为1的对象。对于那些未遵守这些约定,却做了类似操作的方法,可以使用__attribute__((ns_returns_retained))来标明,但如果方法遵守了命名约定,就不必再修饰。

还有很多,不一一赘述,这篇文章中有较为细致的讲解:(传送门)。


结语:

尽管本文列举了很多attribute,但它们仍然只是GCC/Clang中有关attribute的一小部分。

尽管在代码中我们可以从不使用attribute,但了解和使用attribute仍然会带给我们巨大的收益:

这不仅仅体现在通过合理使用attribute,做到更好的编译器优化、编译器检查、内存管理、自动代码生成等;

更重要的是通过这些attribute,能够使得代码的可读性、可维护性得到大大提高,让后继者能拥有一份赏心悦目的代码未尝不是一件值得高兴的事呢。

参考资料:

https://nshipster.com/__attribute__/

http://www.unixwiz.net/techtips/gnu-c-attributes.html

https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

https://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Type-Attributes.html

https://clang.llvm.org/docs/AttributeReference.html

https://blog.sunnyxx.com/2016/05/14/clang-attributes/

http://blog.sunnyxx.com/2014/09/15/objc-attribute-cleanup/

https://segmentfault.com/a/1190000003887934

https://medium.com/@liushuaikobe/%E4%B8%8Eclang%E5%85%B1%E8%88%9E-attribute-8b6bc839958c

相关文章

网友评论

      本文标题:__attribute__(编译属性)知识总结

      本文链接:https://www.haomeiwen.com/subject/vifoaxtx.html