Domanda

Mi chiedo come posso definire un oggetto in C il cui riferimento sarà nullo?

// definition of foo 
...
void * bar = &foo; // bar must be null

Ci sono alcuni modi che potrei trovare per farlo, ma nessuno soddisfa le mie esigenze.

__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

In realtà, preferirei una soluzione conforme allo standard (c99), ma tutto ciò che funziona sarà ok.


Modificato:Il motivo per farlo è che la barra non sarà sempre nulla.Ecco un esempio più rilevante:

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

Naturalmente questo non è ancora molto rilevante, perché posso usare #if nelle mie condizioni.Il progetto coinvolge infatti grandi strutture, moltissimi file, pochi compilatori, qualche CPU target e molti programmatori che generano bug con una probabilità esponenziale alla complessità della sintassi che utilizzano.È per questo che vorrei una semplice macro per dichiarare il mio oggetto foo.

È stato utile?

Soluzione

Stai provando a creare un simbolo con un indirizzo pari a zero. Il tuo ultimo esempio è probabilmente l'unico modo per farlo all'interno del compilatore / linguaggio C.

L'approccio che molto probabilmente risolverà il tuo problema è quello di guardare il file di input al programma linker. La maggior parte dei linker ti consente di definire l'etichetta foo come zero.

In uno script unix ld questo è solo: foo = 0;

Altri suggerimenti

Mi manca qualcosa, ma cosa non funziona su void * bar = NULL?

Nella tua classe, puoi ignorare l'operatore &:

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

Questo produce un comportamento che un utente di MyClass probabilmente non si aspetterebbe. Non sono sicuro di dove & Quot; caratteristica & Quot; sarebbe richiesto o addirittura voluto.

Se vuoi prendere l'indirizzo reale di un'istanza boost, puoi usare MyClass::operator&() (come suggerito nei commenti a questa risposta):

MyClass foo;

MyClass *fooptr = &foo; // fooptr == NULL
fooptr = boost::addressof(foo); // fooptr = &foo (the real address)

Oppure puoi usare il casting, quindi <=> non viene chiamato:

struct DummyStruct {};

MyClass foo;

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

Quello che vuoi è un riferimento che contiene un indirizzo null. Questa è una pratica estremamente negativa, ma qui va:

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

Per favore, non farlo in questo modo. auto_ptr potrebbe essere un'opzione migliore.

Ok, deve essere la domanda, ma vuoi avere un puntatore con un valore pari a 0?

che ne dite di

void * bar = (void*) 0;

Non devi fare tutto questo casino riguardo a:un puntatore è semplicemente un numero a cui il compilatore associa un tipo;se vuoi che il numero sia 0, assegna 0.

Oh, e rispondendo ad un'altra domanda, non è che la lingua abbia qualcosa a che fare con questo, è solo che non sai necessariamente cosa si trova nella posizione 0.Abbiamo avuto molti problemi con il codice BSD in passato perché sui primi unix BSD, *0 == 0 era affidabile in modo affidabile.Quindi le persone scriverebbero cose come

while(*c) doSomething();

perché quando hanno dereferenziato 0x00 alla fine di una stringa, hanno guardato LOCATION 0 che aveva VALUE 0.Sfortunatamente, ciò non era necessariamente vero su altre piattaforme.

Dubito davvero che ci sia un modo per farlo nello standard C99. Nel C ++ standard, sarebbe difficile fare riferimento all'oggetto una volta creato, se fosse possibile crearlo, poiché la dereferenziazione di una costante puntatore null non è definita e uno 0 costante integrale nella costante puntatore è una costante puntatore null. (Sì, potresti provare int i; i = 0; foo * p = reinterpret_cast<foo *>i; p->doSomething(); ma lo standard non specifica cosa fa reinterpret_cast & Lt; & Gt; se non in modo vago e dipendente dall'implementazione.)

Quindi, la mia prossima domanda è cosa stai cercando di realizzare qui. Se stai cercando di distorcere la lingua in modi strani e interessanti, ciò non cambia in base allo standard. Se hai un uso legittimo per questo, quale sarebbe?

Penso che tu sia vicino, solo un passo del puntatore indiretto lontano.

A giudicare dall'esempio di codice, non è necessario prendere l'indirizzo di foo. Puoi realizzare ciò che desideri creando una funzione che alloca e crea un'istanza bar.

Quindi invece di:

DECL(foo);

int * bar = &foo;

potresti avere:

#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();

Nota che questo elimina completamente la variabile free(bar).

L'unica avvertenza è che ora è necessario <=>.

Bene, ecco cosa abbiamo:

  • C++ consente l'overload operator& e dispone di modelli che fanno il lavoro per te, ma non consente di dereferenziare il puntatore nullo.
  • C consente di dereferenziare il puntatore nullo, a condizione che l'indirizzo venga preso successivamente.Permette anche l'assegnazione void* a qualsiasi puntatore a un oggetto.

Beh, è ​​l'ideale.Innanzitutto la parte C, che è molto semplice.Non capisco il tuo punto secondo cui non puoi incorporarlo nelle macro.Funziona bene per me.

#define foo_ (*(void*) 0)

Ora, la parte C++.Inserisci il materiale in nullp.hpp:

struct nullp { 
    struct proxy { 
        template<typename T> operator T*() { 
            return 0; 
        } 
    }; 

    proxy operator&() { 
        return omg(); 
    } 
} foo; 

Ora, tutto ciò che dobbiamo fare è incollare insieme le cose:

#ifdef __cplusplus
#include "nullp.hpp"
#else
#define foo (*(void*) 0)
#endif

Ora puoi usare &foo e assegnarlo a qualche puntatore a qualche tipo di oggetto.

Senti, mi dispiace, ma stai rendendo tutto questo troppo difficile e troppo complicato.

Se vuoi chiamare la cosa in C, hai bisogno di un puntatore per funzionare. Quindi, ad esempio, hai

/* 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 */

Ora, nel codice successivo puoi farlo

if(!func) 
    (*func)();
else
    /* function not defined */

Non devi fare confusione con il caricatore e non hai bisogno di --- e non dovresti usare --- eventuali macro zippy a meno che tu davvero davvero hanno una forte ragione per farlo. Questo è tutto standard C.

Non penso che ci sia un modo standard per definire qualcosa che abbia l'indirizzo 0. O piuttosto, non è definito poiché sarebbe quindi possibile dereference 0, che è indefinito (o è specifico della piattaforma?) nello standard .

Cosa stai cercando di fare?

Se stai usando C ++, puoi usare riferimenti:

int *foo = 0;
int &bar = *foo;
int *foo_addr = &bar; // gives NULL
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top