【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;会给你带来麻烦 

posted on 2022-10-04 01:22  bdy  阅读(620)  评论(0编辑  收藏  举报

导航