记住 container_of
的一个方法是将其视为一个宏,它接受三个参数:指向成员变量的指针、结构体类型和成员变量的名称。例如:
#define container_of(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
这个宏的作用是返回包含给定成员变量的结构体的指针。要使用它,您需要提供一个指向成员变量的指针、结构体类型和成员变量的名称。例如:
struct my_struct {
int a;
int b;
};
// 指向 my_struct 中的某个成员变量的指针
struct my_struct *ptr = { .a = 1,.b = 2 };
// 获取包含该成员变量的 my_struct 结构体的指针,并访问其 b 成员变量
int b = container_of(ptr, struct my_struct, b)->b;
记住 container_of
的另一个方法是理解其实现原理。它使用了 C 语言中的指针算术和结构体偏移量来计算包含给定成员变量的结构体的指针。具体来说,它使用 offsetof
宏来计算成员变量在结构体中的偏移量,然后从成员变量的指针中减去该偏移量,得到包含该成员变量的结构体的指针。
在C语言中,可以使用结构体初始化器来初始化结构体的成员。结构体初始化器是一组用花括号括起来的值,每个值对应结构体中的一个成员。
例如,假设有以下结构体定义:
struct Person {
char name[20];
int age;
float height;
};
可以使用以下方式初始化结构体成员:
struct Person p1 = {"John", 25, 1.75};
这将创建一个名为p的Person结构体,并将其成员初始化为"John"、25和1.75。
如果只想初始化结构体的部分成员,可以使用以下方式:
struct Person p = {.name = "John", .age = 25};
这将创建一个名为p的Person结构体,并将其name成员初始化为"John",age成员初始化为25,而height成员将被初始化为0(因为没有指定它的值)。
这里使用了大括号 {}
来初始化结构体 p1
的成员变量。大括号中的值按照结构体定义中成员变量的顺序进行初始化,即第一个值对应 name
,第二个值对应 age
,第三个值对应 height
。
这里使用了大括号 {}
来初始化结构体 p2
的成员变量,但只初始化了 name
和 age
,height
的值将默认为0。在大括号中,使用成员变量名来指定要初始化的成员变量,这样可以避免按照顺序初始化时出现错误。
在C语言中,结构体初始化器使用逗号分隔每个成员的值。这是因为结构体中的每个成员都是独立的,它们的值可以分别指定。
例如,还是上面的结构体定义:
struct Person {
char name[20];
int age;
float height;
};
可以使用以下方式初始化结构体成员:
struct Person p = {"John", 25, 1.75};
如果使用其他分隔符,例如分号,那么编译器将无法正确解析结构体初始化器,因为分号在C语言中通常用于表示语句的结束。因此,逗号是结构体初始化器中成员值的正确分隔符。
在正式代码中,用逗号分隔一组结构体成员赋值语句,如下:
struct AudioHeader hdr;
hdr.file_id = LC3_FILE_ID,
hdr.header_size = sizeof(AudioHeader),
hdr.channels = nchannels,
hdr.nsamples_low = nsamples & 0xffff,
hdr.nsamples_high = nsamples >> 16,
在正式代码中,用逗号分隔一组结构体成员赋值语句是错误的。这种写法在语法上是不正确的,因为逗号分隔符只能用于分隔表达式,而不是语句。
在这种情况下,编译器可能会将每个成员赋值语句视为单独的语句,并在语法上将其视为正确的。但是,这种写法可能会导致代码难以阅读和维护,因为它不符合通常的结构体成员赋值语法。正确的写法应该是使用分号来分隔每个结构体成员赋值语句,如下所示:
struct AudioHeader hdr;
hdr.file_id = LC3_FILE_ID;
hdr.header_size = sizeof(AudioHeader);
hdr.channels = nchannels;
hdr.nsamples_low = nsamples & 0xffff;
hdr.nsamples_high = nsamples >> 16;
这一点,编译器没有报错,回头再查查资料。