神奇的__attribute__

__attribute__是GNU C特色之一,在iOS用的比較廣泛宠互。如果你沒有用過畏线,那系統(tǒng)庫你總用過,在Foundation.framework中有很多地方用到__attribute__特性良价。__attribute__ 可以設置函數(shù)屬性(Function Attribute )寝殴、變量屬性(Variable Attribute )和類型屬性(Type Attribute )蒿叠。接下來就從iOS中常見用法談起。

1. format

作用:編譯器會檢查格式化字符串與“...”的匹配情況蚣常,防止產(chǎn)生難以發(fā)現(xiàn)的Bug市咽。

用法:

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

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

其中參數(shù)m與n的含義為:

m 格式化字符串(format string)的位置(順序從1開始);

n 參數(shù)“…”的位置(順序從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

作用:告訴編譯器該方法不可用贞绳,如果強行調(diào)用編譯器會提示錯誤谷醉。比如某個類在構造的時候不想直接通過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

作用:用于帶有數(shù)值類型參數(shù)的函數(shù)上。當重復調(diào)用帶有數(shù)值參數(shù)的函數(shù)時萎攒,由于返回值是相同的遇八,所以此時編譯器可以進行優(yōu)化處理,除第一次需要運算外耍休, 其它只需要返回第一次的結(jié)果就可以了刃永,進而可以提高效率。該屬性主要適用于沒有靜態(tài)狀態(tài)和副作用的一些函數(shù)羊精,并且返回值僅僅依賴輸入的參數(shù)斯够。(const參數(shù)不能用在帶有指針類型參數(shù)的函數(shù)中,因為該屬性不但影響函數(shù)的參數(shù)值园匹,同樣也影響到了參數(shù)指向的數(shù)據(jù)雳刺,它可能會對代碼本身產(chǎn)生嚴重甚至是不可恢復的嚴重后果。)

用法:

__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

作用:離開作用域之后執(zhí)行指定的方法裸违。實際應用中可以在作用域結(jié)束之后做一些特定的工作掖桦,比如清理。

用法 :__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;
}
//結(jié)合宏定義使用
#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函數(shù)之前執(zhí)行,__attribute__((destructor)) 在main函數(shù)之后執(zhí)行供汛。__attribute__((constructor(PRIORITY)))和__attribute__((destructor(PRIORITY)))按優(yōu)先級執(zhí)行枪汪。(可用于動態(tài)庫注入的Hook)

用法:
__attribute__((constructor))

__attribute__((destructor))

__attribute__((constructor(PRIORITY)))

__attribute__((destructor(PRIORITY)))

PRIORITY 為優(yōu)先級

例子:

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

作用:定義有返回值的函數(shù)時扶欣,而實際情況有可能沒有返回值艰毒,此時編譯器會報錯晋修。加上attribute((noreturn))則可以很好的處理類似這種問題伴奥。

用法:
__attribute__((noreturn))

例子:

void __attribute__((noreturn)) onExit();

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

9. nonnull

作用:編譯器對函數(shù)參數(shù)進行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字節(jié)對齊方式惜论。packed該屬性對struct 或者union 類型進行定義凯旭,設定其類型的每一個變量的內(nèi)存約束惫霸,當用在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/

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市卤唉,隨后出現(xiàn)的幾起案子涩惑,更是在濱河造成了極大的恐慌,老刑警劉巖桑驱,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竭恬,死亡現(xiàn)場離奇詭異,居然都是意外死亡熬的,警方通過查閱死者的電腦和手機痊硕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悦析,“玉大人寿桨,你說我怎么就攤上這事∏看鳎” “怎么了亭螟?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長骑歹。 經(jīng)常有香客問我预烙,道長,這世上最難降的妖魔是什么道媚? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任扁掸,我火速辦了婚禮,結(jié)果婚禮上最域,老公的妹妹穿的比我還像新娘谴分。我一直安慰自己,他們只是感情好镀脂,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布牺蹄。 她就那樣靜靜地躺著,像睡著了一般薄翅。 火紅的嫁衣襯著肌膚如雪沙兰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天翘魄,我揣著相機與錄音鼎天,去河邊找鬼。 笑死暑竟,一個胖子當著我的面吹牛斋射,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绩鸣,長吁一口氣:“原來是場噩夢啊……” “哼怀大!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起呀闻,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎潜慎,沒想到半個月后捡多,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡铐炫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年垒手,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倒信。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡科贬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鳖悠,到底是詐尸還是另有隱情榜掌,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布乘综,位于F島的核電站憎账,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏卡辰。R本人自食惡果不足惜胞皱,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望九妈。 院中可真熱鬧反砌,春花似錦、人聲如沸萌朱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嚷兔。三九已至森渐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冒晰,已是汗流浹背同衣。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留壶运,地道東北人耐齐。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親埠况。 傳聞我的和親對象是個殘疾皇子耸携,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容