如何定义地址为null的对象?

时间:2009-01-16 16:51:26

标签: c++ c linker weak-references

我想知道如何在C中定义一个对象,其引用将为null?

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

我有一些方法可以做到这一点,但没有一种方法符合我的需要。

__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

实际上,我更喜欢符合标准的解决方案(c99),但任何有效的方法 没关系。


编辑:执行此操作的原因是bar不会始终为null。这是一个更相关的例子:

// 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);
}

当然这仍然不是很相关,因为我可以在我的条件下使用#if。该项目实际上涉及大型结构,大量文件,一些编译器,一些cpu目标,以及许多程序员,他们生成的错误概率指数与他们使用的语法的复杂性呈指数关系。这就是为什么我想要一个简单的宏来声明我的foo对象。

11 个答案:

答案 0 :(得分:16)

我必须遗漏一些东西,但是对于void * bar = NULL什么不起作用?

答案 1 :(得分:2)

在您的课程中,您可以覆盖&运算符:

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;
};

这会产生MyClass的用户可能不会期望的行为。我不确定这个“功能”在哪里需要甚至想要。

如果您想获取MyClass个实例的真实地址,可以使用boost(根据此答案的评论中的建议):

MyClass foo;

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

或者您可以使用强制转换,因此不会调用MyClass::operator&()

struct DummyStruct {};

MyClass foo;

MyClass *fooptr = &foo; // fooptr == NULL
fooptr = &reinterpret_cast<DummyStruct>(foo); // fooptr = &foo (the real address)

答案 2 :(得分:2)

您想要的是一个包含空地址的引用。这是非常糟糕的做法,但这里有:

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

请不要这样做。 auto_ptr可能是更好的选择。

答案 3 :(得分:1)

您正在尝试创建地址为零的符号。您的最后一个示例可能是在C编译器/语言中执行此操作的唯一方法。

最有可能解决问题的方法是查看链接器程序的输入文件。大多数链接器允许您将标签foo定义为零。

在unix ld脚本中,这只是: foo = 0;

答案 4 :(得分:0)

我认为没有一种标准的方法可以定义地址为0的东西。或者更确切地说,它是未定义的,因为它可以在标准中取消引用0,这是未定义的(或者它是特定于平台的?)

你想做什么?

答案 5 :(得分:0)

好的,这是问题,但你想要一个值为0的指针?

怎么样

void * bar = (void*) 0;

你不必做所有那些搞乱:指针只是编译器与一个类型相关联的数字;如果您希望数字为0,请指定0。

哦,回答另一个问题,并不是语言与它有任何关系,只是你不一定知道位置0的内容。我们在当天遇到了很多BSD代码的麻烦,因为在早期的BSD unices中,* 0 == 0是可靠的。所以人们会写像

这样的东西
while(*c) doSomething();

因为当他们在字符串末尾取消引用0x00时,它会查看LOCATION 0,其值为0.不幸的是,在其他平台上并不一定如此。

答案 6 :(得分:0)

我真的怀疑在标准C99中有办法做到这一点。在标准C ++中,如果你可以创建它,你将很难引用该对象,因为取消引用空指针常量是未定义的,并且指针常量中的常量整数0是空指针常量。 (是的,您可以尝试int i; i = 0; foo * p = reinterpret_cast<foo *>i; p->doSomething();,但标准没有指定reinterpret_cast&lt;&gt;做什么,除了模糊和依赖于实现的方式。)

所以,我的下一个问题是你在这里想要完成的事情。如果你试图以奇怪而有趣的方式扭曲语言,那么根据标准,它不会扭曲。如果你有合法的用途,它会是什么?

答案 7 :(得分:0)

我认为你很接近,只是指针间接的一步。

根据您的代码示例判断,无需使用foo的地址。 您可以通过创建分配和实例化bar的函数来完成您想要的任务。

所以而不是:

DECL(foo);

int * bar = &foo;
你可以:

#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();

请注意,这完全消除了变量foo

唯一需要注意的是,您现在需要free(bar)

答案 8 :(得分:0)

嗯,这就是我们所拥有的:

  • C ++允许重载operator&并具有模板来为您完成工作,但不允许解除引用空指针。
  • C允许解除引用空指针,只要之后获取地址即可。它还允许将void*分配给任何指向对象的指针。

嗯,那是理想的。首先,C部分,这很容易。我不明白你的观点,你不能把它嵌入到宏中。它对我来说很好。

#define foo_ (*(void*) 0)

现在,C ++部分。把东西放在nullp.hpp:

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

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

现在,我们需要做的就是把事情粘在一起:

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

现在,您可以使用&foo并将其指定给指向某个对象类型的指针。

答案 9 :(得分:0)

看,我很抱歉,但你这太难了太复杂了。

如果你想在C中调用这个东西,你需要一个指向函数的指针。所以,例如,你有

/* 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 */

现在,在以后的代码中你可以做

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

你不需要搞乱加载器,你不需要---也不应该使用---任何zippy宏,除非你真的 真的有充分的理由这样做。这都是标准C。

答案 10 :(得分:-1)

如果您使用的是C ++,则可以使用引用:

int *foo = 0;
int &bar = *foo;
int *foo_addr = &bar; // gives NULL