views:

263

answers:

5

I'm working with a library that redefines NULL. It causes some problems with other parts of my program. I'm not sure what I can do about it. Any idea? My program's in C++, the library's in C.

#ifdef NULL
#undef NULL
#endif

/**
 * NULL define.
 */
#define NULL    ((void *) 0)

Oh, and it produces these errors:

Generic.h:67: error: default argument for parameter of type 'LCD::LCDBase*' has type 'void*'
Generic.cpp: In constructor 'LCD::Generic::Generic(std::string, Json::Value*, int, LCD::LCDBase*)':
Generic.cpp:44: error: invalid conversion from 'void*' to 'QObject*'
Generic.cpp:44: error:   initializing argument 2 of 'LCD::LCDWrapper::LCDWrapper(LCD::LCDInterface*, QObject*)'
Generic.cpp: In member function 'void LCD::Generic::BuildLayouts()':
Generic.cpp:202: error: invalid conversion from 'void*' to 'LCD::Widget*'
Generic.cpp: In member function 'void LCD::Generic::AddWidget(std::string, unsigned int, unsigned int, std::string)':
Generic.cpp:459: error: invalid conversion from 'void*' to 'LCD::Widget*'
scons: *** [Generic.o] Error 1

Here's the first one:

Generic(std::string name, Json::Value *config, int type, LCDBase *lcd = NULL);

Edit: Ok, casting explicitly works, but how do I cast for a function pointer?

+5  A: 

Can you rebuild the library without that define? That's what I'd try first. NULL is a pretty standard macro, and should be assumed to be defined everywhere.

Right now, your problem is that C++ doesn't allow automatic casts from void * to other pointer types like C does.

From C++ Reference:

In C++, NULL expands either to 0 or 0L.

If that doesn't work, just do a global replace in the library: NULL to LIBDEFINEDNULL or something. That way you'll keep the library code intact and avoid the macro collision.

Jurily
I thought about that, but the library likely redefined it for an internal reason. That'll be the last thing I try. I'm going to try and cast NULL appropriately.
Scott
I chatted with someone on the lib's IRC channel. He's not sure why NULL was redefined. I went ahead and just removed it from the library, and it compiled fine.
Scott
Fascinating. That one belongs on the DailyWTF! Thanks for the update!
Toji
+3  A: 

Do you have access to that libraries source? If so, I think a search and replace on their code is in order. (Replace their NULL with LIBNAME_NULL or something similar.) If that's simply not an option then I would recommend using 0 in your code instead of NULL.

I'm curious, though: What problems is that causing? They're not changing the value of null, only the default casting.

Toji
In C you can implicitly cast from void* to all pointer types. In C++ you can't. Since the library defines it to ((void*)0) he's having problems with C++ code.
asveikau
+1 Oh, hey, you already had this idea.
Jurily
Ah, good point asveikau. I've been doing some C interfaces lately, so I'm kinda stuck in that mindset :)
Toji
+3  A: 

The most generic approach would be to wrap up the offending includes and store and restore the macros previous definition. This, however, is compiler-dependent.
This is how you could do it with VC:

#pragma push_macro("NULL")
#include <offendinglib.h>
#pragma pop_macro("NULL")

Alternatively, set the macro to what you need it to be afterwards:

#include <offendinglib.h>
#undef NULL
#define NULL 0
Georg Fritzsche
not quite should be #define NULL 0
Joshua
Yes, thanks for the edit John :)
Georg Fritzsche
A: 

Yes, you do just need to cast appropriately:

Generic(std::string name, Json::Value *config, int type,
    LCDBase *lcd = (LCDBase *)NULL);
Justice
You are not supposed to be needing casts from `NULL` to `T*` in C++.
Georg Fritzsche
gf, but that library redefines NULL so it won't cast implicitly.
Scott
Bad idea. Misses the point of the NULL macro. If you write code that casts NULL, people will look at your code and think you're dumb. :-)
asveikau
If i am not mixing up anything: the library is in C and redefines in the headers, the problem seems to be resulting from includes from the C library into the C++ code.
Georg Fritzsche
Sounds like the library is "to blame", so fix the library. Don't mess up all your own code to "fix" the library's problem.
Craig McQueen
+3  A: 

One of your comments says you've considered redefining it yourself, but you don't know what to redefine it to.

A lot of implementations will define NULL like this:

#undef NULL

#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif

This is because in C, it makes sense to have it as a void pointer, because it's a pointer type that can be implicitly cast to other types.

C++ doesn't allow this (which is causing your problems), but using 0 instead of NULL works.

I think in all recent versions, GCC will actually define it to __null, which is a non-portable extension.

asveikau