__attribute__ 总结

attribute是GNU C特色之一,在iOS用的比较广泛.系统中有许多地方使用到. attribute可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute)等.

函数属性(Function Attribute)

  • 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
  • nonnull

类型属性(Type Attributes)

  • aligned
  • packed
  • transparent_union,
  • unused,
  • deprecated
  • may_alias

变量属性(Variable Attribute)

  • aligned
  • packed

Clang特有的

  • availability
  • overloadable

书写格式

书写格式:attribute后面会紧跟一对原括弧,括弧里面是相应的attribute参数

__attribute__(xxx)

常见的系统用法

format

官方例子:NSLog

 #define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A)))

format属性可以给被声明的函数加上类似printf或者scanf的特征,它可以使编译器检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。该功能十分有用,尤其是处理一些很难发现的bug。对于format参数的使用如下
format (archetype, string-index, first-to-check)
第一参数需要传递“archetype”指定是哪种风格,这里是 NSString;“string-index”指定传入函数的第几个参数是格式化字符串;“first-to-check”指定第一个可变参数所在的索引.

noreturn

官方例子: abort() 和 exit()

该属性通知编译器函数从不返回值。当遇到类似函数还未运行到return语句就需要退出来的情况,该属性可以避免出现错误信息。

availability

官方例子:

 
  1. - (CGSize)sizeWithFont:(UIFont *)font NS_DEPRECATED_IOS(2_0, 7_0, "Use -sizeWithAttributes:") __TVOS_PROHIBITED;

  2.  
  3. //来看一下 后边的宏

  4. #define NS_DEPRECATED_IOS(_iosIntro, _iosDep, ...) CF_DEPRECATED_IOS(_iosIntro, _iosDep, __VA_ARGS__)

  5.  
  6. define CF_DEPRECATED_IOS(_iosIntro, _iosDep, ...) __attribute__((availability(ios,introduced=_iosIntro,deprecated=_iosDep,message="" __VA_ARGS__)))

  7.  
  8. //宏展开以后如下

  9. __attribute__((availability(ios,introduced=2_0,deprecated=7_0,message=""__VA_ARGS__)));

  10. //ios即是iOS平台

  11. //introduced 从哪个版本开始使用

  12. //deprecated 从哪个版本开始弃用

  13. //message 警告的消息

availability属性是一个以逗号为分隔的参数列表,以平台的名称开始,包含一些放在附加信息里的一些里程碑式的声明。

  • introduced:第一次出现的版本。

  • deprecated:声明要废弃的版本,意味着用户要迁移为其他API

  • obsoleted: 声明移除的版本,意味着完全移除,再也不能使用它

  • unavailable:在这些平台不可用

  • message:一些关于废弃和移除的额外信息,clang发出警告的时候会提供这些信息,对用户使用替代的API非常有用。

  • 这个属性支持的平台:ios,macosx。

简单例子:

 
  1. //如果经常用,建议定义成类似系统的宏

  2. - (void)oldMethod:(NSString *)string __attribute__((availability(ios,introduced=2_0,deprecated=7_0,message="用 -newMethod: 这个方法替代 "))){

  3. NSLog(@"我是旧方法,不要调我");

  4. }

  5.  
  6. - (void)newMethod:(NSString *)string{

  7. NSLog(@"我是新方法");

  8. }

效果:

Paste_Image.png

//如果调用了,会有警告

Paste_Image.png

unavailable

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

 
  1. //系统的宏,可以直接拿来用

  2. #define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable))

  3.  
  4. #define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE

 
  1. @interface Person : NSObject

  2.  
  3. @property(nonatomic,copy) NSString *name;

  4.  
  5. @property(nonatomic,assign) NSUInteger age;

  6.  
  7. - (instancetype)init NS_UNAVAILABLE;

  8.  
  9. - (instancetype)initWithName:(NSString *)name age:(NSUInteger)age;

  10.  
  11. @end

Paste_Image.png

//实际上unavailable后面可以跟参数,显示一些信息,如:

 
  1. //系统的

  2. #define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))

objc_root_class

表示这个类是一个根类(基类),比如NSObject,NSProxy.

 
  1. //摘自系统

  2. //NSProxy

  3. NS_ROOT_CLASS

  4. @interface NSProxy <NSObject> {

  5. Class isa;

  6. }

  7.  
  8. //NSObject

  9. __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0)

  10. OBJC_ROOT_CLASS

  11. OBJC_EXPORT

  12. @interface NSObject <NSObject> {

  13. Class isa OBJC_ISA_AVAILABILITY;

  14. }

NSObject
@property (nonatomic,strong) __attribute__((NSObject)) CFDictionaryRef myDictionary;

CFDictionaryRef属于CoreFoundation框架的,也就是非OC对象,加上attribute((NSObject))后,myDictionary的内存管理会被当做OC对象来对待.

objc_designated_initializer

用来修饰类的designated initializer初始化方法,如果修饰的方法里没有调用super类的 designated initializer,编译器会发出警告。可以简写成NS_DESIGNATED_INITIALIZER

这篇文章讲的很好,建议参考这个.
https://yq.aliyun.com/articles/5847

visibility

语法:

__attribute__((visibility("visibility_type")))

其中,visibility_type 是下列值之一:

  • default
    假定的符号可见性可通过其他选项进行更改。缺省可见性将覆盖此类更改。缺省可见性与外部链接对应。

  • hidden
    该符号不存放在动态符号表中,因此,其他可执行文件或共享库都无法直接引用它。使用函数指针可进行间接引用。

  • internal
    除非由 特定于处理器的应用二进制接口 (psABI) 指定,否则,内部可见性意味着不允许从另一模块调用该函数。

  • protected
    该符号存放在动态符号表中,但定义模块内的引用将与局部符号绑定。也就是说,另一模块无法覆盖该符号。

  • 除指定 default 可见性外,此属性都可与在这些情况下具有外部链接的声明结合使用。
    您可在 C 和 C++ 中使用此属性。在 C++ 中,还可将它应用于类型、成员函数和命名空间声明。

系统用法:

 
  1. // UIKIT_EXTERN extern

  2. #ifdef __cplusplus

  3. #define UIKIT_EXTERN extern "C" __attribute__((visibility ("default")))

  4. #else

  5. #define UIKIT_EXTERN extern __attribute__((visibility ("default")))

  6. #endif

  7.  
  8. `

nonnull

编译器对函数参数进行NULL的检查,参数类型必须是指针类型(包括对象)
//使用

 
  1. - (int)addNum1:(int *)num1 num2:(int *)num2 __attribute__((nonnull (1,2))){//1,2表示第一个和第二个参数不能为空

  2. return *num1 + *num2;

  3. }

  4.  
  5. - (NSString *)getHost:(NSURL *)url __attribute__((nonnull (1))){//第一个参数不能为空

  6. return url.host;

  7. }

常见用法

aligned

__attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐.例如:

不加修饰的情况

 
  1. typedef struct

  2. {

  3. char member1;

  4. int member2;

  5. short member3;

  6. }Family;

  7.  
  8. //输出字节:

  9. NSLog(@"Family size is %zd",sizeof(Family));

  10. //输出结果为:

  11. 2016-07-25 10:28:45.380 Study[917:436064] Family size is 12

//修改字节对齐为1

 
  1. typedef struct

  2. {

  3. char member1;

  4. int member2;

  5. short member3;

  6. }__attribute__ ((aligned (1))) Family;

  7.  
  8. //输出字节:

  9. NSLog(@"Family size is %zd",sizeof(Family));

  10. //输出结果为:

  11. 2016-07-25 10:28:05.315 Study[914:435764] Family size is 12

和上面的结果一致,因为 设定的字节对齐为1.而结构体中成员的最大字节数是int 4个字节,1 < 4,按照4字节对齐,和系统默认一致.

修改字节对齐为8

 
  1. typedef struct

  2. {

  3. char member1;

  4. int member2;

  5. short member3;

  6. }__attribute__ ((aligned (8))) Family;

  7.  
  8. //输出字节:

  9. NSLog(@"Family size is %zd",sizeof(Family));

  10. //输出结果为:

  11. 2016-07-25 10:28:05.315 Study[914:435764] Family size is 16

这里 8 > 4,按照8字节对齐,结果为16,不知道字节对齐的可以看我的这篇文章http://www.jianshu.com/p/f69652c7df99

可是想了半天,也不知道这玩意有什么用,设定值小于系统默认的,和没设定一样,设定大了,又浪费空间,效率也没提高,感觉学习学习就好.

packed

让指定的结构结构体按照一字节对齐,测试:

 
  1. //不加packed修饰

  2. typedef struct {

  3. char version;

  4. int16_t sid;

  5. int32_t len;

  6. int64_t time;

  7. } Header;

  8.  
  9. //计算长度

  10. NSLog(@"size is %zd",sizeof(Header));

  11. 输出结果为:

  12. 2016-07-22 11:53:47.728 Study[14378:5523450] size is 16

可以看出,默认系统是按照4字节对齐

 
  1. //加packed修饰

  2. typedef struct {

  3. char version;

  4. int16_t sid;

  5. int32_t len;

  6. int64_t time;

  7. }__attribute__ ((packed)) Header;

  8.  
  9. //计算长度

  10. NSLog(@"size is %zd",sizeof(Header));

  11. 输出结果为:

  12. 2016-07-22 11:57:46.970 Study[14382:5524502] size is 15

用packed修饰后,变为1字节对齐,这个常用于与协议有关的网络传输中.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 这个错误提示意味着在调用Python的vars()函数时,传入的参数不是一个带有__dict__属性的对象。vars()函数用于返回一个对象的属性和属性值的字典。 通常情况下,vars()函数可以接受任何具有__dict__属性的对象作为参数,例如Python内置的对象类型(如字典、列表、字符串等),或者自定义的类实例。但如果传入的参数不具有__dict__属性,那么就会出现上述的错误提示。 ### 回答2: “vars()”函数是Python内置的一个函数,用于返回一个对象的字典形式,包括对象的属性和值。当我们使用vars()函数时,参数必须是一个拥有__dict__属性的对象。 在Python中,每个对象都有一个字典形式的属性__dict__,存储了该对象的所有属性和对应的值。当我们调用vars()函数时,它会返回这个字典。 如果我们传递给vars()函数的参数不具备__dict__属性,就会出现错误信息“vars() argument must have __dict__ attribute”。 为什么要求参数具备__dict__属性呢?这是因为vars()函数的实现机制决定的。我们知道,vars()函数返回的是对象的属性和值,而这些属性和值都存储在对象的__dict__属性中。因此,只有具备__dict__属性的对象,才能正常的返回属性和值的字典形式。 举个例子,如果我们定义一个空的类,该类没有定义属性也没有实例化对象,那么这个类就没有__dict__属性,因为它没有任何属性需要存储。因此,如果我们尝试对这个类调用vars()函数,就会出现“vars() argument must have __dict__ attribute”的错误。 总结来说,vars()函数要求参数具有__dict__属性是因为它的实现机制需要读取对象的属性和值,并将其以字典形式返回。如果参数没有__dict__属性,就无法正常进行存储和读取操作,因此会报错。 ### 回答3: 当我们调用`vars()`函数时,我们必须给它传递一个具有`__dict__`属性的参数。`__dict__`属性是一个字典,它保存了对象的所有属性和对应的值。 这个错误通常发生在我们试图将一个不具备`__dict__`属性的对象作为参数传递给`vars()`函数时。这意味着该对象没有一个字典来保存其属性。例如,如果我们传递一个整数或一个函数作为参数,都会抛出这个错误。 正确的使用方法是,我们应该传递具有`__dict__`属性的对象给`vars()`函数。通常情况下,我们可以使用普通的自定义类的实例或内置的一些对象(如模块、类实例)作为`vars()`函数的参数。 要解决此错误,我们可以确保传递给`vars()`函数的对象具有`__dict__`属性。如果使用的是自定义类,可以在类定义中添加`__dict__`属性。对于一些内置的对象,我们可以直接使用。如果无法修改对象本身,我们可以考虑使用其他函数来获取对象的属性和值,例如`dir()`函数。这样我们就可以避免`vars()`调用时出现这个错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flybirding10011

谢谢支持啊999

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值