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

发布于 2024-07-11 14:40:18 字数 845 浏览 10 评论 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 对象。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

抚你发端 2024-07-18 14:40:19

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

怎么样?

void * bar = (void*) 0;

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

哦,回答另一个问题,这并不是语言与它有任何关系,只是你不一定知道位置0中是什么。我们有很多过去 BSD 代码遇到了麻烦,因为在早期的 BSD unices 上, *0 == 0 确实是 true。 因此人们会这样写,

while(*c) doSomething();

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

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.

み格子的夏天 2024-07-18 14:40:19

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

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

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?

最好是你 2024-07-18 14:40:19

我认为你已经很接近了,只差指针间接一步了。

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

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

风铃鹿 2024-07-18 14:40:19

好吧,这就是我们所拥有的:

  • 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 并将其分配给某个指向某种对象类型的指针。

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.

巴黎夜雨 2024-07-18 14:40:19

听着,我很抱歉,但你让这件事变得太难、太复杂了。

如果你想在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。

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.

っ〆星空下的拥抱 2024-07-18 14:40:19

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

你想做什么?

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?

街角卖回忆 2024-07-18 14:40:19

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

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

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

int *foo = 0;
int &bar = *foo;
int *foo_addr = &bar; // gives NULL
撞了怀 2024-07-18 14:40:18

我肯定遗漏了一些东西,但是 void * bar = NULL 不起作用吗?

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

输什么也不输骨气 2024-07-18 14:40:18

在您的类中,您可以重写 & 运算符:

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)

或者您可以使用强制转换,所以 < code>MyClass::operator&() 未被调用:

struct DummyStruct {};

MyClass foo;

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

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)
回忆躺在深渊里 2024-07-18 14:40:18

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

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

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

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.

若有似无的小暗淡 2024-07-18 14:40:18

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

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

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

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 ;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文