mingw + offsetof() doesn't work

Started by
3 comments, last by krajzega 19 years, 8 months ago
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

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
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]
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?
Quote:Original post by Gyrbo
BTW, What a POD-type anyway?

POD means Plain Old Data.
Problems with Windows? Reboot! - Problems with Linux? Be root!
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".

This topic is closed to new replies.

Advertisement