1 year ago

#383826

test-img

glades

Get class member from next member's address

I'm wrapping a C interface and require to pass into it the address of a preallocated buffer. My wrapper places this buffer at a known location within wrapper object A. At runtime, I will be able to query the API for its buffer address. I need to be able to somehow get the wrapper object address however. Now this is what I've come up with:

  • This is a simplified testcase: std::array buf_ represents the buffer I'm passing into the C function.
  • The function glean_ptr() simulates the behavior of the API: it returns the pointer to the buffer.
  • I then want to be able to determine the address of the wrapping object A from the buffer address -> I packed it in a substruct and decrease its address.

DEMO

#include <iostream>
#include <array>

struct A
{
    A() : obj_{this} {}

#pragma pack(1)
    struct B {
        A* self_;
        std::array<int, 10> buf_;
    } obj_;

    auto glean_ptr() { return &obj_.buf_; }

    void say_hello() { std::cout << "hello" << std::endl; }
};

int main()
{
    A a;

    auto ptr = a.glean_ptr();

    // do some hacking

    A* b = reinterpret_cast<A*>(ptr)-1;

    b->say_hello();
}

I have two questions:

  • Will this always work? It works in the DEMO, but I'm planning to use it on a microcontroller (32 bit registers).
  • The compiler is not able to see through this I think. Might there a better way to achieve the same result without ugly reinterpret_cast?

EDIT according to @François Andrieux's suggestions (only array pointer arithmetics is defined in C++ standard):

DEMO

#include <iostream>
#include <array>

struct TCB_ // struct of which the C API returns a handle to
{
    int a;
    int b;
    char c;
    long long d;
};

struct A
{
    A() : buf_{this} {}

    static constexpr size_t S_ = (1+sizeof(TCB_)/sizeof(A*) + !!(sizeof(TCB_)%sizeof(A*)));
    std::array<A*, S_> buf_;

    TCB_* glean_ptr() { return reinterpret_cast<TCB_*>(&buf_[1]); }

    void say_hello() { std::cout << "hello" << std::endl; }
};

int main()
{
    A a;

    auto ptr = a.glean_ptr();

    // do some hacking

    A* b = reinterpret_cast<A*>(ptr)-1;

    b->say_hello();
}

c++

c++17

wrapper

reinterpret-cast

class-members

0 Answers

Your Answer

Accepted video resources