IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> iOS 编译器__Attribute__的入门指南 -> 正文阅读

[移动开发]iOS 编译器__Attribute__的入门指南

作者:小朋鸟

一、Attribute

Attribute 是 GNU C 的一大特色。
所以这对于iOS来说这是一个什么东西?

  • 这是一个可以给对象或函数声明特性的编译器指令,目的是让编译器做更多的错误检查和优化。
  • 可设置函数属性(Function Attribute)、变量属性(Variable Attribute)、类型属性(Type Attribute)

Swift 文档中的说明:

Attributes provide more information about a declaration or type. There are two kinds of attributes in Swift, those that apply to declarations and those that apply to types.

属性提供关于声明或类型的更多信息。Swift中有两种属性,一种应用于声明,另一种应用于类型。

引用:Attributes

二、使用方法

以下列举一下要怎么使用,大概的场景是什么。

1、内存对齐,深度优化

// aligned 用来调整内存对齐中每行的位数
// 如果设置少于4,编译器会自动优化成4
// 最大也只能是8
struct stu{
    char sex;
    int length;
    char name[2];
    char value[16];
}__attribute__((aligned(16)));

struct stu my_stu;

NSLog(@"%lu", sizeof(my_stu));
NSLog(@"%p %p,%p,%p", &my_stu,&my_stu.length,&my_stu.name,&my_stu.value);
NSLog(@"Hello, World!");

2、强制内联

减少函数调用,不过要注意递归方法不能用内联。

// 如果使用 __attribute__((always_inline))
// 汇编中会减少callq的方法
__attribute__((always_inline)) void inlineFunction(){
    int a = 10; a+= 10;
}

void testInline(){
    inlineFunction();
}

testInline();

对于以上两点,你可以永远相信编译器,除非哪一天它欺骗了你。那你再去尝试优化。

3、规范提醒

可以直接通过警告或者报错,提醒别人不能这样做!

/* 
    OC中可以是用 #param mark - xxxx
    swift使用   #MARK - xxxxx
*/
// 在父类中某个被重写的方法上添加这个,编译器会提醒子类的重写方法中调用[super]
__attribute__((objc_requires_spuer))



//deprecated(gnu::deprecated)
//用来表示废弃api
//第一个参数是废弃的消息,第二个是建议用来替代的函数
void func(void) __attribute__((deprecated("message","replacement")));



//diagnose_if 用来添加一些函数调用时需要满足的条件,会在编译时发出警告或者提醒
//不会发出运行时的的警告。
int  tabs(int a)
__attribute__((diagnose_if(a >= 0, "Redundant abs call", "warning")));

int must_abs(int a)
__attribute__((diagnose_if(a >= 0, "Redundant abs call", "error")));

int val = tabs(1);    //warning
int val2 = must_abs(1);//error
int val3 = tabs(val);//nothing
int val4 = must_abs(val);//nothing


//enable_if,刚好和 diagnose_if 的条件设置相反
void func(int a)__attribute__((enable_if(a>0 && a<120,"我是xx"))) {
    NSLog(@"11:%d",a);
}

func(1000); //报错:No matching function for call to 'func'

4、语法转换

// 将 struct 和 union 转换成 NSValue
// __attribute__((objc_boxable))
// 然后可以使用NSValue的语法糖。
struct __attribute__((objc_boxable)) _people {
    int year;
    NSString *name;
};

union __attribute__((objc_boxable)) _student {
    int class;
};

typedef struct __attribute__((objc_boxable)) _people people;
people p;
NSValue *boxed = @(p);

5、黑魔法

具体想做什么,可以参考下面示例。

// constructor/destructor,构造器和析构器,可以在main函数之前和之后调用函数
// constructor 的调用会比load方法晚一点
// destructor 会调用在exit函数之前。
// 可以调整他们的调用优先级。后面的参数就是优先级
// __attribute_((constructor(101))) 【0-100】是系统保留了,不能占用,数字越小越优先
// constructor 可以用来做很坏的事情,因为load方法已经加载完成了,内存中已经有被加载类的信息。
__attribute__((constructor))
void funca(){
    print("beforeMain");
}

__attribute__((destructor))
void funcb(){
    print(@"beforeExit");
}

/* 
   参考sunnyxx大大的一句话:剩下的就全靠想象力了,😂 
*/

监听变量作用域结束时,调用指定函数。

// 用在一个对象上,当变量的作用域结束时,调用一个指定函数
// 调用时机会比 dealloc 早
// 作用域结束包括:return、goto、break、exception
// 注意传入类型要一样
__attribute__((cleanup(func)))

void func(__strong NSString **value){
    NSLog(*value);
}

int main() {
    // 这里会输出 hello world
    NSString *str __attribute__((cleanup(func))) = @"hello world";
    return 0;
}
  • ReactiveCocoa 中 @onExit 宏的例子,SDWebImage 中也是这样的,很像swift中的defer。
// void(^block)(void)的指针是void(^*block)(void)
static inline void blockCleanUp(__strong void(^*block)(void)) {
    (*block)();
}

// 定义 onExit
#define onExit __strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^

// 使用方式
onExit {
    NSLog(@"我最后才输出!");
}

6、混淆加固

这可以用来做编译加固,但可能会影响到一些动态调用,要慎重。

// 可以用在interface和protocol上,将类名或者协议名在编译期换成指定名字
__attribute__((objc_runtime_name("xxx")))

7、声明函数不返回

  • 表明执行完成后,函数不返回给调用方。exit() 函数是 _Noreturn 函数的一个示例,一旦调用exit() 它不会往下执行了。
  • 和 void 返回类型不同的是,void 类型的函数再执行完毕后返回主调函数,只是它不提供返回值。
_Noreturn void func(int a ){
    print(a)
}
  • AFNetworking 中的例子,__attribute__((noreturn)) 类似于 Swift 中的返回值类型为 Never 的函数。
// 生成独立的网络 NSThread 时启动一个 NSRunLoop 循环处理,以确保分离的线程在应用程序的生命周期内继续执行。
+ (void) __attribute__((noreturn)) networkRequestThreadEntryPoint:(id)__unused object {
    do {
        @autoreleasepool {
            [[NSRunLoop currentRunLoop] run];
        }
    } while (YES);
}

8、判断检查

//__has_attribute 用来检测是否有attribute属性
#if __has_feature(attribute_ns_returns_retained)
    #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#else
    #define NS_RETURNS_RETAINED
#endif

9、禁止衍生子类

// 在类前面添加,该类就无法添加子类,如果添加了,会编译出错。
__attribute__((objc_subclassing_restricted))
@interface Person: NSObject

三、clang 新增的特性

1、新的弃用声明

添加了更多参数:

  • introduced 首次定义
  • deprecated 弃用版本
  • obsoleted 废弃版本
  • unavailable 平台无效
  • message=string-literal 在废弃或者弃用版本的提示
  • replacement=string-literal 该api的代替
void func(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
// 这个参数列表有没有感觉像 @#available()

2、C 中重载一个C++函数

// 在C中重载一个C++函数,C中的函数重载是使用可重载属性引入的。
__attribute__((overloadable)))

#include <math.h>

float __attribute__((overloadable)) tgsin(float x) { 
    return sinf(x); 
}

double __attribute__((overloadable)) tgsin(double x) { 
    return sin(x); 
}

long double __attribute__((overloadable)) tgsin(long double x) { 
    return sinl(x); 
}

3、提前分配指针空间

优化大佬专用。

// alloc_size 需要和 __builtin_object_size 一起使用
// alloc_size 也只能最多两个参数,参数的意义就是指定函数的第几个形参
// 根据我们传入的值的大小,从 __builtin_object_size 中获取的就是多少
// 如果有两个参数,那么就会是两个参数的大小相乘的结果。
// 这个就是给指针绑定了空间大小了

void *my_malloc(int a) __attribute__((alloc_size(1)));
void *my_callocd(int a, int b, int m) __attribute__((alloc_size(1,3)));
void *my_malloc(int a) {
    return NULL;
}
void *my_callocd(int a, int b, int m){
    return NULL;
}

void *const p = my_malloc(100);
NSLog(@"%d", __builtin_object_size(p,1));

void *const a = my_callocd(20,3,5);
NSLog(@"%d", __builtin_object_size(a,2));

四、小结

Attribute 还有很多很多的使用没有列举,因为实在是太多了。

这就当是编译器前端的一点小学习笔记吧。编译器作为计算机三大浪漫之一,是没有那么容易被攻克的。

计算机三大浪漫

  • 编译原理
  • 操作系统
  • 图形学

欢迎大家一起在评论区交流~

欢迎关注我们,了解更多 iOS 和行业技术的动态~

五、参考

  1. Attributes — The Swift Programming Language (Swift 5.5)
  2. Attribute用法1
  3. Attribute用法2
  4. Attribute说明
  5. GCC文档说明
  6. CPP文档说明
  7. cleanup的用法
  8. noreturn的说明
  9. ReactiveCocoa 中奇妙无比的“宏”魔法
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-01 14:01:50  更:2022-01-01 14:06:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 4:22:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码