2015-07-03 4 views
5

Ich habe eine Reihe von (Zeiger) Arrays von verschiedenen Längen, die ich habe ich gelernt, konnte unter Verwendung der Verbindung Literale definieren:Clang beschwert: „Zeiger durch ein temporäres Array initialisiert wird“

const uint8_t *const minutes[] = { 
    (const uint8_t[]) {END}, 
    (const uint8_t[]) {1, 2, 3, 4, 5 END}, 
    (const uint8_t[]) {8, 9, END}, 
    (const uint8_t[]) {10, 11, 12, END}, 
    ... 
}; 

gcc dies akzeptiert nur gut, aber Klang sagt: pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression. Was bedeutet das? Der Code scheint zu funktionieren, aber andererseits scheinen viele Dinge zu funktionieren, wenn sie auf Speicher zeigen, der nicht mehr zugeordnet ist. Muss ich mir deswegen Sorgen machen? (Letztendlich brauche ich es nur wirklich, um mit gcc zu arbeiten.)

Update: Etwas faul ist los. Es sagt here dass:

Compound literals yield lvalues. This means that you can take the address of a compound literal, which is the address of the unnamed object declared by the compound literal. As long as the compound literal does not have a const-qualified type, you can use the pointer to modify it.

`struct POINT *p; 
    p = &(struct POINT) {1, 1}; 

Dieses Beispiel Code genau zu tun scheint, was ich versuche zu tun: durch eine Verbindung wörtliche definiert einen Zeiger auf etwas. Also ist die Clam-Fehlermeldung legitim? Wird dies auf nicht zugewiesenen Speicher zeigen, wenn entweder mit clang oder gcc kompiliert wird?

Update 2: fand einig documentation: „In C wird eine Verbindung Literal bezeichnet ein unbenannte Objekt mit statischer oder dynamischer Speicher Dauer In C++ ist eine Verbindung literal ein temporäres Objekt bezeichnet, die sie nur bis zum Ende lebt. "So scheint es, dass clang ist richtig, davor zu warnen, und gcc wahrscheinlich sollte auch, aber nicht, auch mit -Wall -Wextra.

Ich kann nicht erraten, warum ein nützliches C-Feature aus C++ entfernt wurde, und es wurde kein eleganter alternativer Weg gefunden, dasselbe zu erreichen.

+0

kompilieren Sie mit '-W-Flag bei Verwendung von gcc?Es könnte sich zeigen, wenn Sie nicht – GeoffreyB

+0

Yep sind. -Wall -Wextra, das ist anscheinend das Gleiche. – Josh

+0

haben Sie versucht, das unnötige '(const uint8_t [])' am Anfang jeder Zeile zu entfernen? –

Antwort

3

Nun, Klirren ist richtig, und das soll auch so geschehen:

namespace elements 
{ 
    const uint8_t row1[] = {END}; 
    const uint8_t row2[] = {1, 2, 3, 4, 5, END}; 
    ... 
} 
const uint8_t *const minutes[] = { 
    elements::row1, 
    elements::row2, 
    ... 
}; 

Sie können mehr C++ denken Lösung, wie std::tuple mit:

#include <tuple> 

constexpr auto minutes = std::make_tuple(
    std::make_tuple(), 
    std::make_tuple(1,2,3,4,5), 
    std::make_tuple(8,9,10)); 

#include <iostream> 
#include <type_traits> 
int main() { 
    std::cout << std::tuple_size<decltype(minutes)>::value << std::endl; 
    std::cout << std::tuple_size<std::remove_reference_t<decltype(std::get<1>(minutes))>>::value << std::endl; 
} 
+0

Warum mag ich Ihre erste Option nicht: es ist chaotisch. Es ist anfällig für Tippfehler. Wenn ich die Zeilen neu anordne oder später eine Zeile hinzufüge, müssen viele Variablen umbenannt werden, oder die Zeilennummern müssen nicht mehr in der richtigen Reihenfolge stehen. Dennoch scheint es der einfachste Weg zu sein, um die richtige In-Memory-Darstellung der Daten zu erhalten. – Josh

+0

Ich muss in Ihre zweite Option mit Std :: Tuple und Constexpr schauen. Ich bin wohler mit C als C++ (wenn Sie nicht erraten haben - aber ich benutze einige C++ - Bibliotheken für dieses Projekt), und ich bin für ein eingebettetes System mit * winzigen * Speicher codieren, also ich nicht Ich möchte jedes Feature nutzen, wenn ich nicht genau weiß, was hinter dem Vorhang vor sich geht.(Ja, ich erkenne die Design-Philosophie hinter C++, oder OOP im Allgemeinen, ist, dass Sie nicht * müssen * müssen die interne Implementierung zu wissen, aber ... :) – Josh

+0

@Josh Wenn Sie Angst vor der falschen Bestellung - Sie kann 'BOOST_PP_ENUM' verwenden - siehe http://www.boost.org/doc/libs/1_39_0/libs/preprocessor/doc/ref/enum.html. – PiotrNycz

1

Nun, das heißt, dieser Ausdruck

(const uint8_t[]) {1, 2, 3, 4, 5 END}, 

erstellt ein temporäres Objekt — vorübergehend, weil es keinen Namen hat, das über den Ausdruck von dem es ein Teil ist, dauern kann —, die am Ende zerstört werden des vollen Ausdruck, was das bedeutet: Bekomme

definiert „den vollen Ausdruck“, an welcher Stelle alle temporären Objekte zerstört, ein nd das Array von Zeigern minutes enthält Zeiger, die auf zerstört Objekte zeigen, weshalb der Compiler warnt.

Hoffe, dass hilft.

+0

Ja, vermute ich so viel. Also was mache ich * darüber? :) – Josh

+0

Definieren Sie sie zuerst als Array. Oder besser Redesign. Verwenden Sie 'std :: array'. – Nawaz

+0

Können Sie ein Beispiel dafür geben, was Sie meinen? Es muss einen Weg geben, dies zu tun, der nicht das Erstellen von Dutzenden von Variablen mit individuellem Namen erfordert, die ich eigentlich nicht verwenden möchte oder möchte ... oder? Diese zusammengesetzte Literalmethode war eine, die ich von einer Antwort hier auf SO bekommen habe - ist das wirklich falsch? – Josh

2

update: danke an den Hinweis für den Fehler in der ursprünglichen Lösung.

static constexpr uint8_t END = 0xff; 

template<uint8_t...x> 
const uint8_t* make() 
{ 
    static const uint8_t _[] = { x..., END }; 
    return _; 
} 

const uint8_t* const array[] = { 
    make<>(), 
    make<1, 2, 3, 4, 5>(), 
    make<8, 9>(), 
    make<10, 11, 12>() 
}; 
+0

Dies kompiliert, obwohl es die kompilierte App größer macht und es ein wenig mehr Speicher braucht - nicht ideal für ein Embedded-System. Irgendeine Idee warum das ist? Ich bin mir auch nicht sicher, was es tut - wie ich es verstehe, sollte eine statische Variable Speicherplatz reservieren, der zwischen Anrufen an die Funktion bestehen bleibt. Wie also weist diese Funktion bei jedem Aufruf neuen Speicherplatz zu? – Josh

+0

Erzeugt eine statische Funktion pro unterschiedlicher Zahlenreihe. Jede statische Funktion enthält ein statisches Array (und einen versteckten Mutex). Wenn du mehr Gedächtnis sagst, wie viel reden wir? Nach der Optimierung könnte ein paar hundert Bytes den Aufwand für eine einfache Wartung wert sein. –

+0

Hinweis: Für dieselbe Anzahl von Parametern generiert diese Funktion nur 1 Array (gefüllt mit Werten aus dem ersten Aufruf). – deniss