【C/C++】结构体操作|地址计算(宏)|打印结构体
目录
获得一个结构体变量成员在此结构体中的偏移量
linux下开发经常会碰到这2个宏,总结下:
1 #define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )
宏功能:获得一个结构体变量成员在此结构体中的偏移量
1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址,即相对于0的偏移量,要的就这个;
4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型,size_t应该最终为unsigned int类型。
获得一个结构体首地址
linux
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
宏功能:从结构体(type)某成员变量(member)指针(ptr)来求出该结构体(type)的首指针。
(参考Linux内核中关于通用型双向链表的实现。具体用到container_of和typeof实现。)
微软
在windows ddk中提供了一个经典的宏,其定义如下:
#define CONTAININT_RECORD(address, type, field) \
((type*)((PCHAR)(address) - (PCHAR)(&((type*)0)->field)))
这个宏用于取得内存中任何结构体的首地址,要提供的参数是:结构体中某个成员(field)的地址address、结构体的类型type、提供地址那个成员的名字field。
https://www.cnblogs.com/live-in-city/p/3431699.html
如何通过结构体其中一个成员变量访问结构体其他成员变量?
https://www.zhihu.com/question/472589638
遍历
需要类似Java的反射机制。可惜的是,直到最新的C++20版本,反射特性还没有被加入C++标准(本来规划要在C++20中包含的,后来被推迟了)。但好消息是,C++23标准应该就能看到编译期反射特性了。
在现有的标准下,想用反射也不是没有办法,boost库的PFR组件就提供了简单的反射功能:
#include <iostream>
#include <string>
#include "boost/pfr.hpp"
struct some_person {
std::string name;
unsigned birth_year;
};
int main() {
some_person val{"Edgar Allan Poe", 1809};
std::cout << boost::pfr::get<0>(val) // No macro!
<< " was born in " << boost::pfr::get<1>(val); // Works with any aggregate initializables!
std::cout << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809}
}
//链接:https://www.zhihu.com/question/28849277/answer/1748011324
参考boost的其他
struct simple { int a; char b; short d; }; simple x {42, 'a', 3}; std::stringstream ss; boost::pfr::for_each_field( x, [&ss](auto&& val) { ss << val << ' '; } );
Caveat: This requires C++14 or even C++17 to work!
打印结构体的方法
https://stackoverflow.com/questions/17660095/iterating-over-a-struct-in-c
在结构体中,重载 << 操作符
struct A
{
int a;
int b;
std::string c;
friend std::ostream& operator <<(std::ostream& os, A const& a)
{
return os << a.a << '\n'
<< a.b << '\n'
<< a.c << '\n';
}
};
然后想打印的时候,直接 std::cout << 结构体 即可:
int main()
{
A a = {5, 10, "apple sauce"};
std::cout << a;
}
Output:
5
10
apple sauce
请注意,将输出流函数添加到结构体需要以某种方式声明结构体,因此如果有人在尝试实现这一点时遇到错误,那么结构体名称的位置(在本例中为 A)是一个很好的第一个位置看。结构 A { ... };和 typedef struct A { ... } A;都可以,但是 typedef struct { ... } A;会给你带来麻烦