# mingw + offsetof() doesn't work

## Recommended Posts

WitchLord    4677
I was running the test framework on MinGW and came upon a portability problem with the offsetof() macro in stddef.h. The following code works on MSVC but not on MinGW:
//
// This test was designed to test the asOBJ_IS_COMPLEX flag
//
// Author: Andreas Jönsson
//

#include "angelscript.h"
#include <stdio.h>
#include <stddef.h> // offsetof(class, property)

#define TESTNAME "TestComplex"

// A complex class is a class that has a defined constructor or
// destructor, or an overridden assignment operator. Compilers
// normally treat these classes differently in that they are
// returned by reference even though they are small enough to
// fit in registers. This is because of the need of exception
// handling in case something goes wrong.

class CComplexClass
{
public:
CComplexClass() { a = 0xDEADC0DE; }

unsigned long a;
};

static CComplexClass cfunction()
{
CComplexClass c;

return c;
}

static CComplexClass c;

class COutStream : public asIOutputStream
{
public:
void AS_CALL Write(const char *text) {printf(text);}
};

bool TestComplex()
{
bool ret = false;

asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

// If asOBJ_IS_COMPLEX is not specified AngelScript will try to determine the
// type of object by looking at what behaviours are registered for the object.
// Since we are not registering any behaviours this time AngelScript would fail.
engine->RegisterObjectType("complex", sizeof(CComplexClass), asOBJ_IS_COMPLEX);
engine->RegisterObjectProperty("complex", "bits a", offsetof(CComplexClass, a));

engine->RegisterGlobalProperty("complex c", &c);
engine->RegisterGlobalFunction("complex cfunction()", asFUNCTION(cfunction), asCALL_CDECL);

c.a = 0;

COutStream out;
engine->ExecuteString(0, "c = cfunction();", &out, 100, 0);

if( c.a != 0xDEADC0DE )
{
printf("%s: Failed to assign complex object returned from function\n", TESTNAME);
ret = true;
}

engine->Release();

return ret;
}


The error I get is:
g++  -o obj/testcomplex.o -c ../../source/testcomplex.cpp
../../source/testcomplex.cpp: In function bool TestComplex()':
../../source/testcomplex.cpp:56: warning: invalid offsetof from non-POD type 
class CComplexClass'; use pointer to member instead

Have anyone else come upon this problem? What did you do to circumvent it? I'd prefer not to define my own macro, but if that is necessary then I'll do it. Regards, Andreas

##### Share on other sites
krajzega    122
That is really only a warning, but offsetof returns the correct values, so I didn't post it as a problem in the forum.

I did however circumvent it with an int typecast from a pointer to member. Like:

  // instead of:  offsetof(Class, Member)  // I have:  (int)(&Class::Member)

This works under GNU C++ (Linux&MinGW) and under Borland C++ Compiler (just checked). If I recall correctly, the cast is guaranteed to evaluate to the byte offset, but I didn't really check it with the C++ draft. [EDIT: I just checked and found that this cast is not on the guaranteed casts list, so a compiler can return any integer it wants. So, you unfortunately can't use it if you want to be completely on the safe side.]

Another way to circumvent it is having:

Class *foo = new Class;
int byteOffset = (char*)(&foo->member) - (char*)(foo);
delete foo;

This should be perfectly portable, but is rather inconvenient. I will however try to check if the first method is really portable and standard.

If the first way is not standard, you could have a macro in your code that would evaluate to member-pointer-cast under GNU and differently other compilers.

[EDIT]

I tried to develop a solution based on templates and the second solution above - but I ended up only, hm, half solving the problem. The function getByteOffset works, but calling it is a pain, something like:
getByteOffset(new Class(3,3), (&Class::member))

This could be made into a macro, but only for objects that have an implicit constructor (Class::Class(), I'm not sure if it's actually called "implicit"). Other objects would need parameters to create a new object.

[Edited by - krajzega on July 28, 2004 11:14:21 AM]

##### Share on other sites
Gyrbo    187
You can always use an #ifdef. A special marco for VC++ and one for the other compilers:
#ifdef _GNUC_ //I think this is the correct one#define OFFSETOF(class, member) ((int)(&(class)::(member)))#else#define OFFSETOF(class, member) offsetof((class), (member))#endif

BTW, What a POD-type anyway?

##### Share on other sites
Erluk    170
Quote:
 Original post by GyrboBTW, What a POD-type anyway?

POD means Plain Old Data.

##### Share on other sites
krajzega    122
Quote:
 #define OFFSETOF(class, member) offsetof((class), (member))

Unfortunately, this won't work. Macros are not expanded recursively , and offsetof is declared as a macro itself, so it will result in a compiler complaint about undefined func "offsetof".

## Create an account or sign in to comment

You need to be a member in order to leave a comment

## Create an account

Sign up for a new account in our community. It's easy!

Register a new account