0

我想知道如何在 C 中定义一个引用为空的对象?

// 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 并不总是为空。这是一个更相关的例子:

// 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 对象。

4

11 回答 11

16

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

于 2009-01-16T16:54:28.223 回答
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)
于 2009-01-16T17:22:04.563 回答
2

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

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

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

于 2009-01-16T17:56:44.133 回答
1

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

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

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

于 2009-01-16T17:08:33.530 回答
0

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

你想做什么?

于 2009-01-16T17:09:14.667 回答
0

好的,这肯定是个问题,但是您想要一个值为 0 的指针吗?

怎么样

void * bar = (void*) 0;

您不必做所有这些事情:指针只是编译器与类型相关联的数字;如果您希望数字为 0,请分配 0。

哦,回答另一个问题,这与语言无关,只是你不一定知道位置 0 中的内容。我们在早期的 BSD 代码上遇到了很多麻烦,因为在早期的 BSD unices, *0 == 0 是可靠的。所以人们会写这样的东西

while(*c) doSomething();

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

于 2009-01-16T17:20:15.753 回答
0

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

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

于 2009-01-16T17:45:38.370 回答
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).

于 2009-01-16T18:08:22.143 回答
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它并将其分配给指向某些对象类型的指针。

于 2009-01-18T03:46:06.800 回答
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。

于 2009-01-19T06:33:18.063 回答
-1

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

int *foo = 0;
int &bar = *foo;
int *foo_addr = &bar; // gives NULL
于 2009-01-16T17:50:03.477 回答