2014-06-13 7 views
5

bekam ich eine Codezeile, wo dies ziemlich nützlich ist:Ist es schlecht oder falsch, auf Va_arg-Makro als Referenz zuzugreifen?

void *test; 
/*...*/ 
test = &va_arg(arg_list, int); 

ich dies nur versucht wurde, wie ich dachte, das ist ein Makro und nicht eine Funktion ist, so dass es funktionieren könnte. Ich hatte nicht wirklich erwartet, dass es funktioniert, aber es macht genau das, was ich will.

Aber jetzt bin ich nicht sicher über die Lebensdauer der Adresse und andere Risiken, die von diesem Stil auftreten können.

Könnte mir jemand sagen, warum die Verwendung der Referenz der va_arg Wert auf diese Weise ist sicher/unsicher?

+1

Ich sehe nichts in der Spezifikation, die 'va_arg (ap, type)' benötigt, um ein lvalue zu sein. –

+0

@JamesMcNellis Also könnte dies in einigen Umgebungen ungültig sein? – dhein

+0

@ Bedeutung-Angelegenheiten Ich denke, er sagt das Gegenteil. Da der Standard sagt, dass 'va_arg' nur einen Wert zurückgibt, gibt es kein Versprechen, dass Sie die Adresse davon nehmen könnten. Es wäre also unsicher, dies zu tun. – user694733

Antwort

3

C99-Standard, Abschnitt 7.15.1.1 (Hervorhebung von mir):

Die va_arg Makro auf einen Ausdruck erweitert, die die angegebene Typ und den Wert des nächsten Argument in der Anruf hat.

Dies bedeutet, dass va_arg nicht unbedingt zu einem Lvalue ausgewertet wird; Es ist unsicher, die Adresse von dem zu übernehmen, auf das sie expandiert: Ein Lvalue kann als Ausdruck verwendet werden, aber nicht jeder Ausdruck ist ein Lvalue. Betrachten Sie den Ausdruck 3+4. Es macht keinen Sinn, die Adresse davon zu nehmen.

Also, nein, Sie sollten es nicht tun.

UPDATE: Wie in den Kommentaren darauf hingewiesen, verursacht die Übernahme der Adresse eines Ausdrucks, der kein Lvalue ist, einen Kompilierungsfehler. Also, wenn der Code kompiliert, dann sollte es sicher sein. Die Probleme der Unportabilität ergeben sich aus der Tatsache, dass sie möglicherweise nicht auf anderen Plattformen kompiliert wird, bei denen va_arg() auf etwas erweitert wird, das kein Lvalue ist.

+0

Wenn es kein Lvalue ist, wäre das dann kein Kompilierungsfehler? Nicht sicher, warum es unsicher wäre, entweder kompiliert es oder es nicht ... – Mehrdad

+0

@Mehrdad Erweiterung zu einem Ausdruck bedeutet nicht, dass der Ausdruck in diesem speziellen Fall kein Lvalue ist. Es kann der Fall sein, dass es tatsächlich ist, also erfolgreich kompilierend. Aber es gibt nichts im Standard, das dieses Verhalten garantiert, also ist es nicht tragbar. –

+1

Also nur für mich, um es richtig zu machen: die Art, wie ich den Code benutze, könnte zu Kompilierzeitfehlern führen, führt aber nicht zu Laufzeitfehlern? Recht? Die Möglichkeit, nach Alternativen für Systeme zu suchen, bei denen dies nicht möglich ist, könnte zu zusätzlichen Vorteilen führen, kann aber nicht schädlich sein. Habe ich das richtig verstanden? – dhein