cplusplus.co.il

Checking sizeof or the offset of a member

Posted on: 29/10/2009

Suppose we wanted to check the sizeof or the offset of a certain member within our struct (or class), without actually having an instantiated object to run the needed operations on. How would you do that?

Here’s the scenario:

struct S {
    int x;
    int y;
}

int main () {
    // for sizeof: sizeof(S::y) obviously doesn't work..
    // for offset: &S::y is a pointer-to-member, which is wrong..
    // how do we compute these two values?
}

Granted we’re not interested in instantiating a new object to check these values on, we’re in a bit of a pickle here. Luckily, there’s a trick to overcome this.

The following will work:

int main () {
    using std::cout;
    using std::endl;
    cout << "offset: " << &reinterpret_cast<S*>(0)->y << endl;
    cout << "sizeof: " << sizeof(reinterpret_cast<S*>(0)->y) << endl;
}

This is how its done within Linux kernel implementation.

 

As pointed out in the comments below, we’re actually dereferncing a NULL value, which makes the code ill formed according to the standard – although it works on nearly any interesting compiler. To avoid this for the sizeof operation we can use the next neat trick:

S* dummy (); // just define a dummy function
sizeof(dummy()->y); // sizeof only needs the type of the expression

I’m not sure if it could be avoided for the offset-of operation. Looks like the presented implementation is the only way, even according to wikipedia. For a portable version, offsetof() macro from stddef.h should be used, as it is implementation specific.

 

An important side note regarding the member offset calculation: since C++ allows overloading of operator& (address-of operator), it could possibly act differently and return something unexpected. Using a work-around such as boost::addressof will completely solve this issue.

Advertisements

8 Responses to "Checking sizeof or the offset of a member"

In C++0x you can do sizeof(MyClass::Member)

http://en.wikipedia.org/wiki/C%2B%2B0x#Allow_sizeof_to_work_on_members_of_classes_without_an_explicit_object

Btw, NULL dereference is undefined behaviour according to the standard.
So you’d better use offsetof macro instead.

According to wikipedia, the macro offsetof() actually uses the same trick: http://en.wikipedia.org/wiki/Offsetof

#define offsetof(st, m) \
    ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))

That’s right.
But this is a private implementation.
The compiler can do this because it knows better about the implementation, but you shall not do it 🙂

Although you can do smth like:

#if (defined(GCC) && VERSION > 2) && ( defined(MSVC) && VERSION > 6 ) and ( defined(INTEL) && VERSION > 5)
#define SIZEOF_MEMBER(class ,member) ….
#else
#error Undefined behaviour for unknown compilers.
#endif

I agree, although if you look close enough – your list contains nearly every popular compiler. I tried googling and couldn’t find a different implementation.

The post has been slightly updated.

Hi,

You can avoid the deref of a null pointer by using some other suitably aligned constant (like 16384) for the pointer and then subtracting it out again. Ugly, but it works and doesn’t require a dummy object.

Jon

You’re over engineering the ‘sizeof member without instance’ scenario. Remember, ‘sizeof’ is a compile-time construct. No instance of ‘X’ in the following example will be created.

struct X {
  int member;
  X() { std::cout << "X::X()" << std::endl; }
  ~X() { std::cout << "X::~X()" << std::endl; }
};

int main()
{
  std::cout << sizeof( X().member );
  return 0;
}

This is indeed nice and easy for the given case, but it isn’t guaranteed to work in the general case; What would you do if there was no default constructor? Or no public one, at all?

Yes, you’re right. Although I think it was still worth mentioning.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: