0

参照が null になるオブジェクトを 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) を好みますが、動作するものは何でも問題ありません。


編集済み:これを行う理由は、バーが常に 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 オブジェクトを宣言したいのはそのためです。

4

11 に答える 11

16

私は何かが欠けている必要がありますが、何がうまくいかないのvoid * bar = NULLですか?

于 2009-01-16T16:54:28.223 に答える
2

必要なのは、nullアドレスを保持する参照です。これは非常に悪い習慣ですが、ここに行きます:

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

このようにしないでください。auto_ptrがより良いオプションかもしれません。

于 2009-01-16T17:56:44.133 に答える
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 に答える
1

アドレスがゼロのシンボルを作成しようとしています。あなたの最後の例は、おそらく C コンパイラ / 言語内でこれを行う唯一の方法です。

問題を解決する可能性が最も高いアプローチは、リンカー プログラムへの入力ファイルを調べることです。ほとんどのリンカーでは、ラベル foo をゼロとして定義できます。

UNIX ld スクリプトでは、これは次のとおりです。 foo = 0 ;

于 2009-01-16T17:08:33.530 に答える
0

さて、これが私たちが持っているものです:

  • C ++はオーバーロードを許可operator&し、テンプレートを使用して作業を実行しますが、nullポインターの逆参照は許可しません。
  • Cは、後でアドレスが取得される限り、nullポインタの逆参照を許可します。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

さて、それは問題になるはずですが、値が0のポインタが必要ですか?

どうですか

void * bar = (void*) 0;

そんなことをすべてやる必要はありません。ポインタは、コンパイラが型を関連付けるための単なる数値です。番号を0にする場合は、0を割り当てます。

ああ、そして別の質問に答えると、それは言語がそれと関係があるということではありません、それはあなたが場所0に何があるかを必ずしも知らないというだけです。 unices、* 0==0は確実に真でした。だから人々は次のようなことを書くでしょう

while(*c) doSomething();

文字列の最後で0x00を逆参照すると、値が0のLOCATION 0が参照されたためです。残念ながら、他のプラットフォームでは必ずしもそうではありませんでした。

于 2009-01-16T17:20:15.753 に答える
0

ほら、ごめんなさい、でもあなたはこれを難しすぎて複雑すぎています。

CでThingを呼び出したい場合は、関数へのポインターが必要です。だから、例えば、あなたは

/* 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です。

于 2009-01-19T06:33:18.063 に答える
0

アドレス 0 を持つものを定義する標準的な方法はないと思います。または、標準では未定義 (またはプラットフォーム固有ですか?) である 0 を逆参照できるため、未定義です。

あなたは何をしようとしているのですか?

于 2009-01-16T17:09:14.667 に答える
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 に答える
-1

C++ を使用している場合は、参照を使用できます。

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