views:

534

answers:

11

I am wondering how I can define an object in C whose reference will be null?

// definition of foo 
...
void * bar = &foo; // bar must be null

There is some ways I could find to do it, but none fit my needs.

__attribute__((weak)) extern int foo; //not working with cygwin/gcc 3.4
__attribute__((at(0))) int foo;       //only with rvds
#define foo (*(int*) 0)               //cannot be embedded in a macro

Actually, I would prefer a standard compliant solution (c99), but anything working will be ok.


Edited: The reason to do this is that bar will not always be null. Here is a more relevant example:

// macro that will define foo to a real object or to *null
DECL(foo);

int * bar = &foo;

if(bar) {
  // we can call func
  func(bar);
} else {
  // bar undefined
  exit(-1);
}

Of course this is still not very relevant, because I can use #if in my condition. The project involves in fact big structures, a lot of files, a few compilers, some cpu targets, and many programmers who generate bugs with a probability exponential to the complexity of the syntax they use. It is why I would like a simple macro to declare my foo object.

+15  A: 

I've got to be missing something, but what doesn't work about void * bar = NULL?

Yuliy
I'm with you on that one!
Tall Jeff
What we're missing is a clue of what the OP really wants to accomplish, actually.
David Thornley
+1  A: 

You are trying to create a symbol with an address of zero. Your last example is probably the only way of doing this within the C compiler / language.

The approach that is most likely to solve your problem is to look at the input file to the linker program. Most linkers allow you to define the label foo as zero.

In a unix ld script this is just: foo = 0 ;

A: 

I don't think there's a standard way to define something that has the address 0. Or rather, it's undefined since it would then be possible to dereference 0, which is undefined (or is it platform specific?) in the standard.

What are you trying to do?

MSN

MSN
I don't have a C standard handy, but in C++ dereferencing the null pointer is undefined, and a constant 0 in pointer context is a null pointer.
David Thornley
A: 

Okay, it's got to be the question, but you want to have a pointer with a value of 0?

how about

void * bar = (void*) 0;

You don't have to do all that messing about: a pointer is just a number with which the compiler associates a type; if you want the number to be 0, assign 0.

Oh, and answering another question, it's not that the language has anything to do with it, it's just you don't necessarily know what is in location 0. We had a lot of trouble with BSD code back in the day because on early BSD unices, *0 == 0 was reliably true. So people would write things like

while(*c) doSomething();

because when they dereferenced the 0x00 at the end of a string, it looked at LOCATION 0 which had the VALUE 0. Unfortunately, that wasn't necessarily true on other platforms.

Charlie Martin
+2  A: 

In your class, you can override the & operator:

class MyClass
{
    public:
        MyClass() :
            m_isNull(true)
        {
        }

        MyClass(int value) :
            m_isNull(),
            m_value(value)
        {
        }

        int value() const
        {
            /* If null, throw exception, maybe? */

            return m_value;
        }

        bool isNull() const
        {
            return m_isNull;
        }

        /////////////////////////
        // Here's the "magic". //
        /////////////////////////
        MyClass *operator&()
        {
            if(m_isNull)
                return 0;
            return this;
        }

    private:
        bool m_isNull;
        int m_value;
};

This produces behavior a user of MyClass would probably not expect. I'm not sure where this "feature" would be required or even wanted.

If you want to take the real address of a MyClass instance, you can use boost (as suggested in the comments to this answer):

MyClass foo;

MyClass *fooptr = &foo; // fooptr == NULL
fooptr = boost::addressof(foo); // fooptr = &foo (the real address)

Or you can use casting, so MyClass::operator&() isn't called:

struct DummyStruct {};

MyClass foo;

MyClass *fooptr = &foo; // fooptr == NULL
fooptr = &reinterpret_cast<DummyStruct>(foo); // fooptr = &foo (the real address)
strager
I don't think this is C99, though, and that's what he asked for.
David Thornley
@Thornley, The question states "anything working will be ok." Also, the question has been tagged with "c++."
strager
and if he still wants to get teh addy, he can use teh boost::addressof
Johannes Schaub - litb
@litb, I have updated my answer with that, and a non-boost method. Thanks.
strager
A: 

I really doubt there is a way to do this in standard C99. In standard C++, you'd be hard put to reference the object once created, if you could create it, as dereferencing a null pointer constant is undefined, and a constant integral 0 in pointer constant is a null pointer constant. (Yes, you could try int i; i = 0; foo * p = reinterpret_cast<foo *>i; p->doSomething(); but the standard doesn't specify what reinterpret_cast<> does, other than in a vague and implementation-dependent way.)

So, my next question is what you're trying to accomplish here. If you're trying to twist the language in odd and interesting ways, it doesn't twist that way according to the Standard. If you've got a legitimate use for this, what would it be?

David Thornley
A: 

If you're using C++, you can use references:

int *foo = 0;
int &bar = *foo;
int *foo_addr = &bar; // gives NULL
strager
note that dereferencing the null pointer formally is undefined. there are some inconsistencies in the standard about that though. it says it's UB, but it says otherwise in one place: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 . tho probably no compiler will crash on your code.
Johannes Schaub - litb
This is undefined behavior, according to the C++ standard. *foo is dereferencing a null pointer. This can do anything, including appearing to work until the worst posible time.
KeithB
+2  A: 

What you want is a reference that holds a null address. This is extremely bad practice, but here goes:

#ifdef NON_NULL
Foo realFoo;
Foo &foo = realFoo;
#else
Foo &foo = *(Foo*)NULL;
#endif

Please, don't do it this way. auto_ptr may be a better option.

Arkadiy
A: 

I think you're close, just a step of pointer indirection away.

Judging by your code sample, there's no need to take the address of foo. You can accomplish what you want by creating a function that allocates and instantiates bar.

So instead of:

DECL(foo);

int * bar = &foo;

you could have:

#define FOO_IS_NULL 0

int * getFoo() 
{  
    if( FOO_IS_NULL )
    {
        return 0;
    }

    int *tmp = malloc(sizeof(int));
    *tmp = 1234;
    return tmp;
}

int * bar = getFoo();

Note that this gets rid of the variable foo entirely.

The only caveat is that you now need to free(bar).

mskfisher
A: 

Well, here is what we have:

  • C++ allows overloading operator& and has templates to do the work for you, but doesn't allow dereferencing the null pointer.
  • C allows dereferencing the null pointer, as long as the address is taken afterwards. It also allows assigning void* to any pointer to an object.

Well, that's ideal. First, the C part, which is very easy. I don't understand your point that you cannot embed it into macros. It works fine for me.

#define foo_ (*(void*) 0)

Now, the C++ part. Put the stuff in nullp.hpp:

struct nullp { 
    struct proxy { 
        template<typename T> operator T*() { 
            return 0; 
        } 
    }; 

    proxy operator&() { 
        return omg(); 
    } 
} foo;

Now, all we need to do is to glue things together:

#ifdef __cplusplus
#include "nullp.hpp"
#else
#define foo (*(void*) 0)
#endif

Now, you can use &foo and assign it to some pointer to some object-type.

Johannes Schaub - litb
Since when can you dereference a void pointer?
strager
Err, nevermind. I misread your statement. I do get a warning from GCC, though: "dereferencing ‘void *’ pointer". With this kind of hackery, though, I'm sure it can be "safely" ignored (even though I would look for a better solution myself).
strager
yeah, whole stuff is hackerish, but completely standard i believe. comeau also seem to support that view. no warning at least from it :)
Johannes Schaub - litb
In c, it's valid to dereference a `void*` - in C++ it's not valid.
Johannes Schaub - litb
A: 

Look, I'm sorry, but you're making this both too hard and too complicated.

If you want to call the thing in C, you need a pointer to function. So, for example, you have

/* ptr to 0-ary function returning int */
int (*func)() = NULL ;    /* That's all you need. */

// elsewhere ....
int myfunc() { /* do a good thing */ }
func = myfunc ;       /* function name *is* its address */

Now, in later code you can do

if(!func) 
    (*func)();
else
    /* function not defined */

You don't need to mess with the loader, and you don't need --- and shouldn't use --- any zippy macros unless you really really have a strong reason for doing so. This is all standard C.

Charlie Martin