代码之家  ›  专栏  ›  技术社区  ›  calandoa

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

  •  -1
  • calandoa  · 技术社区  · 16 年前

    我想知道如何在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),但是任何有效的解决方案 会好的。


    编辑:这样做的原因是,条形图不会始终为空。下面是一个更相关的例子:

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

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

    11 回复  |  直到 12 年前
        1
  •  1
  •   user30364    16 年前

    您正在尝试创建地址为零的符号。最后一个示例可能是在C编译器/语言中实现这一点的唯一方法。

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

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

        2
  •  16
  •   Yuliy    16 年前

    我一定错过了什么,但什么不管用 void * bar = NULL ?

        3
  •  2
  •   strager    16 年前

    在类中,可以重写 & 操作员:

    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 可能没想到。我不知道在哪里需要这个“功能”。

    如果你想知道 类名 实例,您可以使用 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)
    
        4
  •  2
  •   strager    16 年前

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

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

    请不要这样做。自动节拍可能是更好的选择。

        5
  •  0
  •   Charlie Martin    16 年前

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

    怎么样

    void * bar = (void*) 0;
    

    你不必做那么多麻烦事:指针只是编译器将一个类型与之关联的一个数字;如果你想让这个数字为0,就给0赋值。

    哦,回答另一个问题,并不是语言和它有任何关系,只是你不一定知道位置0中是什么。我们在使用BSD代码时遇到了很多问题,因为在早期的BSD Unices中,*0==0是可靠的。所以人们会写

    while(*c) doSomething();
    

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

        6
  •  0
  •   David Thornley    16 年前

    我真的怀疑在标准C99中是否有这样的方法。在标准C++中,如果创建对象,则很难将其引用,因为未定义空指针常量,指针常量中的常数积分0是空指针常数。(是的,你可以试试 int i; i = 0; foo * p = reinterpret_cast<foo *>i; p->doSomething(); 但该标准并未规定重新解释“强制转换”的功能,而是以一种模糊且依赖于实现的方式进行解释。)

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

        7
  •  0
  •   mskfisher KeithS    16 年前

    我觉得你很接近,只是一步指针间接离开。

    从您的代码示例来看,不需要取 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();
    

    注意,这会去掉变量 完全。

    唯一的警告是你现在需要 free(bar) .

        8
  •  0
  •   Johannes Schaub - litb    16 年前

    好吧,我们有:

    • 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
  •   Charlie Martin    16 年前

    听着,我很抱歉,但你把这件事弄得太复杂了。

    如果你想用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 */
    

    你不需要处理加载程序,也不需要——也不应该使用——任何快速的宏,除非你 真的? 真的? 有充分的理由这样做。这都是C标准。

        10
  •  0
  •   Tim Cooper    12 年前

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

    你想做什么?

        11
  •  -1
  •   strager    16 年前

    如果使用C++,可以使用引用:

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