__attribute__简析

本文介绍了Clang提供的多种源码注释属性,包括禁止继承、强制调用super、构造与析构函数、清理变量等,展示了如何使用这些属性来增强代码的安全性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

__attribute__表示属性,是Clang提供的一种源码注释,方便开发者向编译器表达诉求,一般以__attribute__(*)的方式出现在代码中。为了方便使用,一些常用属性被定义成了宏,经常出现在系统头文件中。比如NS_CLASS_AVAILABLE_IOS(9_0) 就是 __attribute__(availability(9.0)) 这个属性的简单写法。下面介绍一些可能会频繁使用到的属性

objc_subclassing_restricted

这个属性表示一个类不可以被继承。如果我们希望我们写的某个类不被继承,那么只需要在@interface前面加上这个属性即可,这样如果有类继承了此类,在编译的时候就会报错

__attribute__((objc_subclassing_restricted))
@interface NoSon : NSObject
@end
objc_requires_super

这个属性表示子类继承这个方法时必须要调用super方法,否则编译器会给出警告。宏写法是NS_REQUIRES_SUPER

@interface MustCallSuper : NSObject

-(void)testMethod __attribute__((objc_requires_super));
-(void)testMethod1 NS_REQUIRES_SUPER;

@end
constructor / destructor

构造器和析构器,加上这两个属性的函数会在可执行文件load和unload的时候调用,可以简单的理解为在main()函数调用前和return后执行

__attribute__((constructor))
static void beforeMain(void) {
    NSLog(@"beforeMain");
}

__attribute__((destructor))
static void afterMain(void) {
    NSLog(@"afterMain");
}

int main(int argc, const char * argv[]) {
    NSLog(@"main");
return 0;
}

如果有多个constructor想控制优先级的话,可以这样写

__attribute__((constructor(101))),里面的数字越小优先级越高,1 ~ 100 为系统保留
cleanup

这个属性的作用是申明到一个变量上,当这个变量的作用域结束时,调用指定的函数

// 指定一个cleanup方法,注意入参是所修饰变量的地址,类型要一样
// 对于指向objc对象的指针(id *),如果不强制声明__strong默认是__autoreleasing,造成类型不匹配
static void stringCleanUp(__strong NSString **string) {
    NSLog(@"%@", *string);
}

// 在某个方法中:
{
    __strong NSString *string __attribute__((cleanup(stringCleanUp))) = @"test";
} 
// 当运行到这个作用域结束时,自动调用stringCleanUp
objc_runtime_name

用于 @interface 或 @protocol,将类或协议的名字在编译时指定成另一个。利用这个特性,一个简单的代码混淆的原型就出来了

__attribute__((objc_runtime_name("NewSon")))
@interface Son : NSObject
@end

NSLog(@"%@", NSStringFromClass([Son class])); // "NewSon"
引用

http://blog.sunnyxx.com/2016/05/14/clang-attributes/

<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` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值