2012-03-27 15 views
3

Vor diesem Prototyp erhalten, die eine Endian Konvertierung tut:Wie die Adresse des Rückgabewert einer Funktion in C++

time_t Flip(time_t); 

Ich möchte den Rückgabewert in einer Funktion verwenden, die eine BYTE nimmt * als ein Argument. Etwas wie folgt aus:

SetBytesAt(0, (BYTE*)&(Flip(t))); 

Aber dies nicht kompiliert. Gibt mir diesen Fehler "& erfordert l-Wert". Wenn die Funktion() um die Flip-Funktion herum entfernt wird, wird derselbe Fehler generiert.

Nun, ich weiß, dass ich dies nur tun können:

time_t temp_t = Flip(t); 
SetBytesAt(0, (BYTE*)&temp_t); 

Aber es scheint mir, dass ich in der Lage sein sollte, die gleiche Sache, ohne die temporären temp_t Variable zu erreichen.

+1

Auf vielen (meisten?) Architekturen befindet sich der von einer Funktion zurückgegebene Wert in einem Register, so dass er/bis er einer Variablen zugewiesen ist, keine Adresse hat. –

+0

Was macht 'SetBytesAt' überhaupt? Wäre irgendwie nützlich zu wissen, um dies richtig zu beantworten ... – leftaroundabout

Antwort

8

Leider nein. Sie können nicht die Adresse eines temporären (richtiger, ein r-value) nehmen. So wurde die Sprache definiert.

+0

-1 "Provisorien (richtiger, R-Werte) haben keine Adressen." ist falsch. Einige von ihnen sind nicht garantiert, Adressen zu haben. Andere haben garantiert Adressen, wenn sie in irgendeiner Weise verwendet werden, die eine Adresse erfordert. Insbesondere können Sie Methoden für Provisorien (rvalues) vom Klassentyp aufrufen. –

+0

@ Cheersandthth.-Alf: Du bist richtig, klar! Ich habe meine Formulierung entsprechend vereinfacht. –

+0

OK, removed downvote :-) –

0

Sie müssen eine temporäre Variable verwenden. Sie können nur Adresse von l-Werten nehmen. Es gibt keine Möglichkeit, die Adresse eines Rückgabewerts zu ermitteln.

Bei einigen Plattformen wird der Rückgabewert nur in einem Register gespeichert und hat daher nicht einmal eine Adresse. Sie müssen es im Speicher speichern, bevor Sie seine Adresse an eine andere Funktion übergeben können.

0

Soweit ich weiß, ist das in C++ nicht möglich.

Fragen Sie sich dies: Wie erhalten Sie Zugriff auf das modifizierte Ergebnis nach SetBytesAt zurückgibt?

Rückgabewerte werden normalerweise in eine tatsächliche Variable in der Aufruferfunktion kopiert (oder verschoben). Der für den zurückgegebenen Wert reservierte temporäre Speicherbereich ist nicht mehr verfügbar, nachdem die Funktion zurückgegeben wurde. Theoretisch würden Sie Speicher stapeln, der nicht mehr gültig ist. Dieser Fehler tritt in der Praxis auf, wenn Referenzen auf lokale Variablen zurückgegeben werden.

+0

Es ist umgekehrt. Der Platz für den Rückgabewert kann verunstaltet werden * weil * der Standard verbietet, dass seine Adresse genommen wird. –

0

Sie können nicht, für den genauen Grund durch die Fehlermeldung angegeben - & requires l-value.

Der Aufruf Flip(t) ist kein l-Wert, also ist es unmöglich.

3

Versuchen Sie das nicht zu Hause.

template <typename T> 
class AddressableTemporary 
{ 
public: 

    AddressableTemporary(T const value) 
     : value_(value) 
    { 
    } 

    operator T*() { return &value_; } 

private: 

    T value_; 
}; 

template <typename T> 
AddressableTemporary<T> MakeAddressable(T value) 
{ 
    return AddressableTemporary<T>(value); 
} 

als:

int F() { return 42; } 
void G(int const* const p) { std::cout << *p; } 

int main() 
{ 
    G(MakeAddressable(F())); 
} 

Aber wirklich, tun dies nicht. Verwenden Sie entweder eine Variable oder schreiben Sie eine Wrapper-Funktion, die die Verwendung der Variablen kapselt, oder bearbeiten Sie Ihren Code neu, sodass Sie sich keine Gedanken darüber machen müssen (z. B. die Funktion so ändern, dass sie beispielsweise eine const-Referenz benötigt).

+1

Und ... jetzt tut mir der Kopf weh. :) – Corbin

+0

Und Sie mussten die Konvertierung implizit machen? –

+0

Schöne Antwort :) Die Macht der Vorlagen noch einmal demonstriert. – Carl

0

Eigentlich wurde es in C++ 11 möglich. Dort wurden r-Wert-Referenzen eingeführt. Ich weiß jedoch nicht, welcher Compiler das schon tut.

+1

Rvalue-Referenzen ermöglichen die Übernahme der Adresse eines R-Werts nicht. –

+0

@JamesMcNellis: warum "magisch"? Natürlich gibt es eine andere Syntax, das Beispiel würde nicht so gehen, wie es ist. Jedoch ist der Fall, dass das OP-Konstrukt mehr oder weniger genau der Grund dafür ist, warum r-Wert-Referenzen eingeführt wurden. – Matthias

0

Es ist keine große Sache zu tun, was Sie wollen, aber es ist unrein.

geht hier:

template< class Type > 
Type const& ref(Type const& v) { return v; } 

int main() 
{ 
    time_t t = blah blah; 
    SetBytesAt(0, const_cast<Byte*>(reinterpret_cast<Byte const*>(&ref(Flip(t))))); 
} 

Technisch kann dies funktionieren, wenn SetBytesAt kopiert das Bytes, aber wenn SetBytesAt speichert den Zeiger, und der Zeiger später verwendet wird, dann ist es nicht definiertes Verhalten.

Wie auch immer, tun Sie das nicht.

Jetzt werde ich Liste, was mit dem ursprünglichen Konzept falsch ist:

  • Typ Wissen Wegwerfen von typenlos Zeiger Argument.
    → Bedeutet viel zusätzliche Arbeit, weil der Typ nicht bekannt ist.

  • Verwerfen von const-Wissen durch Verwendung des Zeigers auf nicht-konstantes Argument.
    → Bedeutet viel zusätzliche Arbeit, weil die Konstanz nicht bekannt ist.

  • Spiegeln Byte Reihenfolge der Daten = nicht gut außer in Low-Level-Netzwerk-Code.
    → Bedeutet viel zusätzliche Arbeit, weil die Byte-Reihenfolge nicht bekannt ist.

Also, wieder, tu das nicht.

Stattdessen das Gegenteil tun: Typ Informationen beibehalten, Konstanz Informationen erhalten, und nicht mit den rohen Bytes verwirren.

Verwandte Themen