__attribute__的一些使用

本文深入探讨Objective-C中的关键编译器属性,包括禁止类被继承、强制调用父类方法、构造和析构函数、方法重载、运行时类名重命名以及变量释放前的清理操作,解析这些属性如何提升代码质量和安全性。
ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

 

1.objc_subclassing_restricted

#import <UIKit/UIKit.h>
#import <objc/runtime.h>
NS_ASSUME_NONNULL_BEGIN

__attribute__((objc_subclassing_restricted))//禁止该类被继承
@interface AAA : UIView
-(void)mustUseMethod;
@end

NS_ASSUME_NONNULL_END

如果某类继承了AAA这个类,那么就会报错

#import "AAA.h"

NS_ASSUME_NONNULL_BEGIN

@interface BBB : AAA  Cannot subclass a class that was declared with the 'objc_subclassing_restricted' attribute

@end

2.objc_requires_super

objc_requires_super 在父类的方法后面添加,那么子类调用该方法必须实现[super thisMethod],否则会黄色警告

@interface Father : NSObject
- (void)mustUseMethod __attribute__((objc_requires_super)); 
@end
@interface Child : TestObject
@end
@implementation BBB
-(void)mustUseMethod{
 //[super mustUseMethod];
    警告信息:(不报错)
Method possibly missing a [super mustUseMethod] call
}
@end

3.constructor / destructor

__attribute__((constructor)) static void beforeMain() { 
   NSLog(@"before main");
}
__attribute__((destructor)) static void afterMain() { 
   NSLog(@"after main");
}
int main(int argc, const char * argv[]) { 
    @autoreleasepool {
          NSLog(@"execute main");
      }
  return 0; 

}

执行结果:
  debug-objc[23391:1143291] before main
  debug-objc[23391:1143291] execute main
  debug-objc[23391:1143291] after main

可以在constructor后边添加设置优先级 

__attribute__((constructor(101))) static void beforeMain() { NSLog(@"before main");
}
__attribute__((constructor(100))) static void beforeMain1() { NSLog(@"before main1");
}
__attribute__((destructor)) static void afterMain() { NSLog(@"after main");
}

执行结果:
2019-10-12 15:48:24.015908+0800 Food[4561:144694] before main1
2019-10-12 15:48:24.016491+0800 Food[4561:144694] before main
2019-10-12 15:48:24.017145+0800 Food[4561:144694] execute main

4.overloadable

可以允许同名函数存在

__attribute__((overloadable)) void testMethod(int age) {NSLog(@"%@", @(age));};
__attribute__((overloadable)) void testMethod(NSString *name) {NSLog(@"%@", name);};
__attribute__((overloadable)) void testMethod(BOOL gender) {NSLog(@"%@", @(gender));};

int main(int argc, char * argv[]) {
    @autoreleasepool {
        testMethod(18);
        testMethod(@"lxz");
        testMethod(YES);
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
执行结果:
2019-10-12 16:01:04.491366+0800 Food[4724:150619] 18
2019-10-12 16:01:04.491510+0800 Food[4724:150619] lxz
2019-10-12 16:01:04.491632+0800 Food[4724:150619] 1

5.objc_runtime_name

objc_runtime_name属性可以在编译时,将Class或者Protocol指定为另一个名字

 

这个属性可以用来做代码混淆,例如写一个宏定义,这个宏定义内部实现混淆逻辑。例如通过MD5对object做混淆,32位的混淆结果就是497031794414a552435f90151ac3b54b,谁能看出来这个是什么类。

__attribute__((objc_runtime_name("TestObject")))
@interface AAA : NSObject

@end



int main(int argc, char * argv[]) {
    @autoreleasepool {
         NSLog(@"--%@",NSStringFromClass([AAA class]));
        
        NSLog(@"----%@",NSClassFromString(@"TestObject"));
  }
}

执行结果:
2019-10-12 16:10:24.414452+0800 Food[4917:156444] --TestObject
2019-10-12 16:10:24.416007+0800 Food[4917:156444] ----TestObject

6.cleanup

通过cleanup属性,可以指定给一个变量,当变量释放之前执行一个函数。指定的函数执行时间,是在dealloc之前。在指定的函数中,可以传入一个形参,参数就是cleanup修饰的变量,形参是一个地址。

static void releaseBefore(NSObject **object) {
    NSLog(@"AAA-------%@", *object);
}
int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        {
           AAA *object __attribute__((cleanup(releaseBefore)))  = [AAA new];
        }
       
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

执行结果:
2019-10-12 16:20:24.230282+0800 Food[5057:162194] AAA-------<AAA: 0x6000021c81d0>
2019-10-12 16:20:24.230633+0800 Food[5057:162194] AAA-dealloc

7.unused

如果某个变量未使用,会提示unused xxx,可以通过unused消除这个警告

int main(int argc, char * argv[]) {
    @autoreleasepool {
     
        AAA *object  __attribute__((unused))  = [AAA new];
      
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>我们正在讨论Linux内核中的属性机制,具体是`kobj_attribute`和`device_attribute`的区别和用途。根据提供的引用内容,我们可以总结如下: 1. **kobj_attribute**: - 引用[1]提到,可以在kobj所在目录下创建一个属性文件,文件名为`attr->name`。这里使用的函数是`sysfs_create_file`和`sysfs_remove_file`,操作对象是`struct kobject`和`struct attribute`。 - `kobj_attribute`结构体通常定义如下(未直接给出,但可推断): ```c struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); }; ``` - 它用于与任意`kobject`关联的属性,提供`show`和`store`函数来读写属性值。 2. **device_attribute**: - 引用[2]给出了`device_attribute`的定义: ```c struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); }; ``` - 引用[3]详细说明了`DEVICE_ATTR`宏,它用于声明设备属性文件。该宏的参数包括属性名、权限、show函数和store函数。 - `device_attribute`是专门为`struct device`设计的,它是对`kobj_attribute`的封装,因为`struct device`内嵌了一个`struct kobject`。 **区别与用途**: - **作用对象不同**: - `kobj_attribute`用于任何`kobject`(它是设备模型的基础,但不仅限于设备)。 - `device_attribute`专用于`struct device`(代表一个设备)。 - **函数参数不同**: - `kobj_attribute`的回调函数接收`struct kobject *`作为第一个参数。 - `device_attribute`的回调函数接收`struct device *`作为第一个参数,这更方便设备驱动开发者,因为可以直接操作设备结构。 - **创建宏不同**: - `kobj_attribute`通常使用`__ATTR`或`__ATTR_RW`等宏来静态初始化。 - `device_attribute`使用`DEVICE_ATTR`宏来声明,该宏会自动生成一个名为`dev_attr_<name>`的结构体变量,并初始化其中的`attr`、`show`和`store`成员。 - **使用场景**: - 当你在为一个设备(如字符设备、总线设备等)创建属性时,应使用`device_attribute`,因为它与设备模型紧密集成,且更方便(例如,在`sysfs`中会自动出现在设备目录下)。 - 当你为其他类型的`kobject`(如一个模块自己的kobject)创建属性时,使用`kobj_attribute`。 **示例**: - 使用`DEVICE_ATTR`声明一个设备属性: ```c static DEVICE_ATTR(foo, 0644, show_foo, store_foo); ``` 然后,在设备驱动中,可以通过`device_create_file`和`device_remove_file`来创建和删除该属性文件。 - 使用`kobj_attribute`则需要自己定义并初始化: ```c static struct kobj_attribute bar_attr = __ATTR(bar, 0644, bar_show, bar_store); ``` 然后,在拥有kobject的地方,使用`sysfs_create_file`来创建。 总结:`device_attribute`是设备驱动中常用的属性类型,它是对`kobj_attribute`的封装,专门用于设备。而`kobj_attribute`则更通用,适用于所有kobject。 §§相关问题§§ 1. 在Linux内核中,如何为一个设备创建多个属性文件? 2. 除了`kobj_attribute`和`device_attribute`,还有哪些类型的属性结构体? 3. 在sysfs中创建属性文件时,权限模式(如0644)中的SUID/GUID位有什么特殊含义吗?</think>### kobj_attribute 与 device_attribute 的区别与用途 在 Linux 内核中,`kobj_attribute` 和 `device_attribute` 都是用于在 sysfs 文件系统中创建属性文件的机制,但它们的应用场景和对象层次不同: #### 1. **kobj_attribute (通用 kobject 属性)** - **作用对象**:面向任意 `kobject` 对象(内核对象的基础抽象) - **结构定义**: ```c struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); }; ``` - **核心用途**: - 为**通用内核对象**(如模块、子系统等非设备对象)创建 sysfs 属性接口 - 通过 `sysfs_create_file()` 直接绑定到 `kobject` 目录[^1] - **操作函数**: - 创建:`sysfs_create_file(kobj, &attr->attr)` - 删除:`sysfs_remove_file(kobj, &attr->attr)` - **适用场景**:驱动核心框架、非设备类内核组件(如内存管理、调度器等) #### 2. **device_attribute (设备专用属性)** - **作用对象**:专用于 `struct device` 对象(代表具体硬件设备) - **结构定义**: ```c struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); }; ``` - **核心用途**: - 为**硬件设备**创建标准化的 sysfs 属性接口(如 `/sys/class/xxx/` 下的设备节点) - 通过宏 `DEVICE_ATTR` 声明属性,自动生成 `dev_attr_<name>` 变量[^3] - **操作函数**: - 创建:`device_create_file(dev, &dev_attr_<name>)` - 删除:`device_remove_file(dev, &dev_attr_<name>)` - **适用场景**:设备驱动程序(如 USB 设备、PCI 设备、传感器等) #### 关键区别总结 | 特性 | `kobj_attribute` | `device_attribute` | |---------------------|-----------------------------------|---------------------------------| | **作用对象** | 通用 `kobject` | 专用 `struct device` | | **层次关系** | 基础层(所有 kobject 均可使用) | 设备层(继承自 kobject) | | **声明宏** | 无标准宏,需手动初始化 | `DEVICE_ATTR(name, mode, show, store)`[^3] | | **参数传递** | `kobject *` | `device *` | | **典型应用位置** | `/sys/kernel/` 等非设备目录 | `/sys/class/` 或 `/sys/bus/` 下的设备目录 | #### 使用示例 **device_attribute 声明**(设备驱动中): ```c static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", read_sensor_temp()); } static DEVICE_ATTR(temperature, 0444, temp_show, NULL); // 声明只读属性 ``` **kobj_attribute 声明**(内核模块中): ```c static ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "Debug mode: %d\n", debug_flag); } static struct kobj_attribute debug_attr = __ATTR(debug, 0644, debug_show, debug_store); ``` #### 选择建议 - 若操作对象是**硬件设备**(如传感器、网卡等),优先使用 `device_attribute` - 若操作对象是**内核通用组件**(如调度器参数、内存池等),使用 `kobj_attribute` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值