神奇的__attribute__

__attribute__是GNU C特色之一,在iOS用的比较广泛。如果你没有用过,那系统库你总用过,在Foundation.framework中有很多地方用到__attribute__特性。__attribute__ 可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute )。接下来就从iOS中常见用法谈起。

1. format

作用:编译器会检查格式化字符串与“...”的匹配情况,防止产生难以发现的Bug。

用法:

__attribute__((format(printf,m,n)))

__attribute__((format(scanf,m,n)))

其中参数m与n的含义为:

m 格式化字符串(format string)的位置(顺序从1开始);

n 参数“…”的位置(顺序从1开始);

例子:

FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
#define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A)))
#define kMaxStringLen 512

extern void MyLog(const char *tag,const char *format,...) __attribute__((format(printf,2,3)));

void MyLog(const char *tag,const char *format,...) {
    va_list ap;
    va_start(ap, format);
    
    char* pBuf = (char*)malloc(kMaxStringLen);
    if (pBuf != NULL)
    {
        vsnprintf(pBuf, kMaxStringLen, format, ap);
    }
    va_end(ap);
    
    printf("TAG:%s Message:%s",tag,pBuf);

    free(pBuf);
}

2. deprecated

作用:使编译会给出过时的警告。

用法:

__attribute__((deprecated))

__attribute__((deprecated(s)))

例子:

#define DEPRECATED_ATTRIBUTE  __attribute__((deprecated))
#if __has_feature(attribute_deprecated_with_message)
  #define DEPRECATED_MSG_ATTRIBUTE(s)  __attribute__((deprecated(s)))
#else
  #define DEPRECATED_MSG_ATTRIBUTE(s)  __attribute__((deprecated))
#endif      

3. availability

作用:指明API版本的变更。

用法:

__attribute__((availability(macosx,introduced=m,deprecated=n)))

m 引入的版本

n 过时的版本

例子:

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

4. unavailable

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

用法:

__attribute__((unavailable))

例子:

#define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable))

#define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE
#import <Foundation/Foundation.h>

@interface Person : NSObject

@property(nonatomic,copy) NSString *name;

@property(nonatomic,assign) NSUInteger age;

- (instancetype)init NS_UNAVAILABLE;

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

@end
066226DB-F65E-4763-B21A-7D8E04B151FF.png

5. const

作用:用于带有数值类型参数的函数上。当重复调用带有数值参数的函数时,由于返回值是相同的,所以此时编译器可以进行优化处理,除第一次需要运算外, 其它只需要返回第一次的结果就可以了,进而可以提高效率。该属性主要适用于没有静态状态和副作用的一些函数,并且返回值仅仅依赖输入的参数。(const参数不能用在带有指针类型参数的函数中,因为该属性不但影响函数的参数值,同样也影响到了参数指向的数据,它可能会对代码本身产生严重甚至是不可恢复的严重后果。)

用法:

__attribute__((const))

例子:

int  __attribute__((const)) add(int x)
{
    printf("%s(%d)\n", __FUNCTION__, x);
    return x + 1;
}
 
int  add2(int x)
{
    printf("%s(%d)\n", __FUNCTION__, x);
    return x + 1;
}
 
int main(int argc, char* argv[])
{
    int i, j;
 
    i = add(10);
    j = add(10);
 
    printf("%d %d\n", i, j);
 
    i = add2(10);
    j = add2(10);
 
    printf("%d %d\n", i, j);
 
    return 0;
}

6. cleanup

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

用法 :__attribute__((cleanup(...)))

例子:


static void stringCleanUp(__strong NSString **string) {
    NSLog(@"%@", *string);
}

void testCleanUp() {
    __strong NSString *string __attribute__((cleanup(stringCleanUp))) = @"stringCleanUp";
}

static void blockCleanUp(__strong void(^ *block)()) {
    if (*block) {
        (*block)();
    }
}

void testBlockCleanUp() {
    __strong void(^block)() __attribute__((cleanup(blockCleanUp))) = ^{
        NSLog(@"block");
    };
}

static void lambdaCleanUp(void (**lambda)()) {
    if (*lambda) {
        (*lambda)();
    }
}

void testLambdaCleanUp() {
    void (*lambda)() __attribute__((cleanup(lambdaCleanUp))) = []() {
        puts("lambda");
    };
}

int main(int argc, char * argv[]) {
   @autoreleasepool {
      testCleanUp();
    
      testBlockCleanUp();
    
      testLambdaCleanUp();
    
   }
 return 0;
}
//结合宏定义使用
#define BlockCleanUp __strong void(^block)() __attribute__((cleanup(blockCleanUp))) = ^
#define LambdaCleanUp void (*lambda)() __attribute__((cleanup(lambdaCleanUp))) = []()
void testDefine() {
    BlockCleanUp {
        puts("BlockCleanUp");
    };
    
    LambdaCleanUp{
        puts("LambdaCleanUp");
    };
}

7. constructor与destructor

作用:__attribute__((constructor)) 在main函数之前执行,__attribute__((destructor)) 在main函数之后执行。__attribute__((constructor(PRIORITY)))和__attribute__((destructor(PRIORITY)))按优先级执行。(可用于动态库注入的Hook)

用法:
__attribute__((constructor))

__attribute__((destructor))

__attribute__((constructor(PRIORITY)))

__attribute__((destructor(PRIORITY)))

PRIORITY 为优先级

例子:

void __attribute__((constructor))  start() {
    NSLog(@"%s",__FUNCTION__);
}

void __attribute__((destructor)) end() {
     NSLog(@"%s",__FUNCTION__);
}


![Uploading E71D5B89-60DF-47C6-A923-F731680F25B6_088963.png . . .]int main(int argc, char * argv[]) {
    
    NSLog(@"%s",__FUNCTION__);
    
    return 0;
}
E71D5B89-60DF-47C6-A923-F731680F25B6.png
void __attribute__((constructor)) start() {
    NSLog(@"%s",__FUNCTION__);
}

void __attribute__((constructor(100)))  start100() {
    NSLog(@"%s",__FUNCTION__);
}

void __attribute__((constructor(101)))  start101() {
    NSLog(@"%s",__FUNCTION__);
}

void __attribute__((destructor)) end() {
    NSLog(@"%s",__FUNCTION__);
}

void __attribute__((destructor)) end100() {
     NSLog(@"%s",__FUNCTION__);
}

void __attribute__((destructor)) end101() {
    NSLog(@"%s",__FUNCTION__);
}

int main(int argc, char * argv[]) {
    
    NSLog(@"%s",__FUNCTION__);
    
    return 0;
}
46182749-3804-40A2-ACA6-691BB2E22B71.png

8. noreturn

作用:定义有返回值的函数时,而实际情况有可能没有返回值,此时编译器会报错。加上attribute((noreturn))则可以很好的处理类似这种问题。

用法:
__attribute__((noreturn))

例子:

void __attribute__((noreturn)) onExit();

int test(int state) {
    if (state == 1) {
        onExit();
    }else {
        return 0;
    }
}

9. nonnull

作用:编译器对函数参数进行NULL的检查

用法:__attribute__((nonnull(...)))

extern void *my_memcpy_2 (void *dest, const void *src, size_t len) __attribute__((nonnull (1, 2)));

extern void *my_memcpy_3 (void *dest, const void *src, const void *other, size_t len) __attribute__((nonnull (1, 2, 3)));

void test_my_memcpy() {
    my_memcpy_2(NULL, NULL, 0);
    my_memcpy_3("", "", NULL, 0);
}
1CA959CA-3710-4F9B-AFC5-A4F263811F6D.png

10. aligned 与 packed

作用:aligned(m) 将强制编译器尽其所能地确保变量在分配空间时采用m字节对齐方式。packed该属性对struct 或者union 类型进行定义,设定其类型的每一个变量的内存约束,当用在enum 类型定义时,暗示了应该使用最小完整的类型。aligned 属性使被设置的对象占用更多的空间,使用packed 可以减小对象占用的空间。

用法:
attribute ((aligned (m)))

attribute ((aligned))

attribute ((packed))

例子:

//运行在iPhone5模拟器上
struct p {
    int a;
    char b;
    short c;
}__attribute__((aligned(4))) pp;

struct m {
    char a;
    int b;
    short c;
}__attribute__((aligned(4))) mm;

struct o {
    int a;
    char b;
    short c;
}oo;

struct x {
    int a;
    char b;
    struct p px;
    short c;
 }__attribute__((aligned(8))) xx;

struct MyStruct {
    char c;
    int  i;
    short s;
}__attribute__ ((__packed__));

struct MyStruct1 {
    char c;
    int  i;
    short s;
}__attribute__ ((aligned));

struct MyStruct2 {
    char c;
    int  i;
    short s;
}__attribute__ ((aligned(4)));

struct MyStruct3 {
    char c;
    int  i;
    short s;
}__attribute__ ((aligned(8)));

struct MyStruct4 {
    char c;
    int  i;
    short s;
}__attribute__ ((aligned(16)));

int main(int argc, char * argv[]) {
    
    printf("sizeof(int)=%lu,sizeof(short)=%lu.sizeof(char)=%lu\n",sizeof(int),sizeof(short),sizeof(char));
    
    printf("pp=%lu,mm=%lu \n", sizeof(pp),sizeof(mm));
    
    printf("oo=%lu,xx=%lu \n", sizeof(oo),sizeof(xx));

    printf("mystruct=%lu \n", sizeof(struct MyStruct));
    
    printf("mystruct1=%lu \n", sizeof(struct MyStruct1));
    
    printf("mystruct2=%lu \n", sizeof(struct MyStruct2));
    
    printf("mystruct3=%lu \n", sizeof(struct MyStruct3));
    
    printf("mystruct4=%lu \n", sizeof(struct MyStruct4));
    
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
DD0CE993-E373-410E-B0CC-5F91C0E56729.png

参考资料:
http://nshipster.com/attribute/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容