2013-08-16 15 views
12

Podczas debugowania niektóre z naszego kodu (C++) Znalazłem to:reinterpret_cast dziwność (oddzielone przecinkiem wyrażenie)

inline std::string BufferToStr(
    const unsigned char* buffer, 
    int index, 
    size_t length) 
{ 
    std::string retValue(reinterpret_cast<const char*>(&buffer[index], length)); 
    return retValue; 
} 

Problem z tym kodem (z widokiem na brak kontroli wskaźnika, a długość łańcucha) jest to, że po zamknięciu nawias reinterpret_cast został umieszczony po length, gdy powinien być po &buffer[index]. Najpierw myślałem, że to jest problem z kompilatorem (używając VS2013), ale po pomyślnym skompilowaniu go przy użyciu VS2012 i gcc 4.6.3, doszedłem do wniosku, że jest to z jakiegoś powodu dozwolone. Kod nie będzie działał w systemie Windows ani Linux, ponieważ parametr długości jest używany jako wskaźnik.

Moje pytanie brzmi: dlaczego to się kompiluje? Patrząc na dokumentację reinterpret_cast nie mogę znaleźć na niej żadnej dokumentacji mówiąc, że możesz przekazać oddzieloną przecinkami listę wartości do niej i co z nią zrobi.

+0

Dlaczego nie należy go skompilować? Mówisz kompilatorowi, żeby rzucił 'size_t' na' const char * ', i to robi. Nie ma sensu być dozwolonym. – Damon

+0

Zauważ, że włączenie ostrzeżenia dałoby wyraźne wskazanie, co się działo, jak pokazałem w mojej odpowiedzi na przykładzie używając 'gcc'. –

Odpowiedz

12

reinterpret_cast przyjmuje numer expression. To, co masz w nawiasie, jest wyrażeniem - "," operator z dwoma podekspozycjami, które będą oceniać wynik ostatniego podekspresji.

+0

Operatorem przecinków była odpowiedź. Zapomniałem o tym. Szybki przegląd sekcji 5.18 w starym podręczniku "The Annotated C++ Reference Manual" Stroustrup wyjaśnił to całkiem dobrze. Dziękuję za szybką odpowiedź. – william

4

To jest comma operator. Ocenia wyrażenia po obu stronach przecinka, ale zwraca wynik wyrażenia prawostronnego.

Powód, dla którego kompilator nie narzeka, polega na tym, że po prostu mówisz kompilatorowi, że wynik wyrażenia (typu size_t) powinien być traktowany jako wyrażenie const char*. To właśnie robi reinterpret_cast, umożliwia rzutowanie prawie dowolnego rodzaju na prawie każdy inny typ, bez względu na to, jak głupi może być.

3
reinterpret_cast <new_type> (expression)   

reinterpret_cast zaakceptować expression. Tutaj masz operatora przecinania, który ocenia wyrażenia po obu stronach i zwraca wyrażenie prawej ręki.

W rzeczywistości wyrażenie (&buffer[index], length) jest tutaj równoważne (length).

Wystarczy zobaczyć: http://msdn.microsoft.com/en-us/library/zs06xbxh.aspx lub http://en.wikipedia.org/wiki/Comma_operator, aby uzyskać wyjaśnienia dla operatora przecinków.

Podsumowując, tutaj mówisz kompilator rzucić size_t (wynik wyrażenia) do const char* i może to zrobić.

7

Wynika to z comma operator w c/C++. Kod (wyrażenie)

(&buffer[index], length) 

to równoważne (& buforze [indeks] ma żadnego wpływu)

(length)

tak Kod odpowiada:

inline std::string BufferToStr(const unsigned char* buffer, int index, size_t length) 
{ 
    std::string retValue(reinterpret_cast<const char*>(length)); 
    return retValue; 
} 
2

Jest to jeden z powodów, dla których ważne jest, aby włączono ostrzeżenia, prawdopodobnie pomogłoby Ci to rozwiązać samodzielnie.Korzystanie gcc i działa z -Wall, jest to ostrzeżenie, które otrzymałem:

warning: left operand of comma operator has no effect [-Wunused-value] 
std::string retValue(reinterpret_cast<const char*>(&buffer[index], length)); 
                   ^

Widać live example.

Ostrzeżenie mówi nam, że używamy comma operator Na początku może to być nieco zaskakujący, ale reinterpret_cast nie jest to wywołanie funkcji, w której to nie będzie działać bez użycia nawiasów jak widzimy in this contrived example, ale wyrazem i w sekcji 5.2Postfix wyrażenia standardu projekt C++ Grammer dla postfix ekspresji zawiera:

postfix-expression: 
    ... 
    reinterpret_cast < type-id > (expression) 
    ... 

i możemy użyć expression w argumencie tak comma operator jest całkowicie poprawny.

+1

Całkowicie się z Tobą zgadzam i zazwyczaj mam poziom ostrzeżenia na -Wall. W tym projekcie został ustawiony na poziomie 3 w Visual Studio i nie wygenerował żadnego ostrzeżenia, zmieniłem go na -Wall, ale nadal nie ostrzegał o tym. Wygląda więc na to, że gcc, przynajmniej w tym przypadku, lepiej raportuje ostrzeżenia. – william

+0

@william Użyłem przykładu 'gcc', ponieważ wspomniałeś, że wypróbowałeś' gcc 4.6.3' oraz 'gcc' z powrotem do co najmniej' 4.4.4' również ostrzega, 'clang' również daje dobre ostrzeżenie. –

Powiązane problemy