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

时间:2021-01-09 14:21:16

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

我想知道如何在C中定义一个对象,其引用将为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.

实际上,我更喜欢符合标准的解决方案(c99),但任何正常工作都可以。


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

编辑:这样做的原因是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);
}

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.

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

11 个解决方案

#1


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.

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

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.

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

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

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

#2


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

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

#3


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.

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

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实例的真实地址,你可以使用boost(如本答案的评论中所建议的):

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:

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

struct DummyStruct {};

MyClass foo;

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

#4


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.

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

#5


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

好的,它必须是问题,但你想要一个值为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.

你不必做所有那些搞乱:指针只是编译器与一个类型相关联的数字;如果您希望数字为0,则指定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

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

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.

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

#6


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.)

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

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?

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

#7


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.

根据您的代码示例判断,不需要获取foo的地址。您可以通过创建分配和实例化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.

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

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

唯一需要注意的是你现在需要*(吧)。

#8


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 ++允许重载operator&并且有模板为你完成工作,但是不允许解除引用空指针。

  • 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.
  • C允许解除引用空指针,只要之后获取地址即可。它还允许将void *赋给任何指向对象的指针。

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.

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

#define foo_ (*(void*) 0)

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

现在,C ++部分。把东西放在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.

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

#9


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

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

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.

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

#10


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.

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

What are you trying to do?

你想做什么?

#11


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

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

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

#1


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.

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

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.

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

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

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

#2


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

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

#3


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.

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

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实例的真实地址,你可以使用boost(如本答案的评论中所建议的):

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:

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

struct DummyStruct {};

MyClass foo;

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

#4


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.

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

#5


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

好的,它必须是问题,但你想要一个值为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.

你不必做所有那些搞乱:指针只是编译器与一个类型相关联的数字;如果您希望数字为0,则指定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

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

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.

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

#6


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.)

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

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?

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

#7


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.

根据您的代码示例判断,不需要获取foo的地址。您可以通过创建分配和实例化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.

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

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

唯一需要注意的是你现在需要*(吧)。

#8


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 ++允许重载operator&并且有模板为你完成工作,但是不允许解除引用空指针。

  • 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.
  • C允许解除引用空指针,只要之后获取地址即可。它还允许将void *赋给任何指向对象的指针。

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.

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

#define foo_ (*(void*) 0)

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

现在,C ++部分。把东西放在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.

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

#9


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

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

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.

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

#10


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.

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

What are you trying to do?

你想做什么?

#11


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

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

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