Pisząc kolejny projekt, miałem sobie oto taki kod:
return this->Send(&msgSize, sizeof(MessageSizeType)) + this->Send(&catLength, sizeof(MessageCatLengthType)) + this->Send(category.c_str(), catLength * sizeof(wchar_t)) + this->Send(msg.c_str(), msg.length() * sizeof(wchar_t));
Nie wydaje mi się bardzo skomplikowany. Powinno wystarczyć, gdy zaznaczę, że wysyła on jedną „wiadomość” przez sieć – ot, 5 pierwszych bajtów to nagłówek(MessageSizeType – unsigned, MessageCatLengthType – unsigned char) a reszta dane. Oczywiście MUSZĄ być one dostarczone wszystkie, w takiej kolejności w jakiej są, więc wszystko leci po TCP. Pytanie: co tu jest źle?
Błędne jest… dodawanie! Tak, to znaczek „+” dość znacznie uprzykrzał mi życie od pewnego czasu. Wszystko było ok., gdy kompilowałem projekt w trybie DEBUG, gdy przełączałem na RELEASE loterią(przynajmniej wtedy dla mnie) było, czy zadziała, czy nie. Był to jeden z dziwniejszych „błędów”, jakie popełniłem. Co się okazało? Kompilator, w ramach „optymalizacji”(ktoś wytłumaczy mi, jakie to optymalizacje?), przestawiał poszczególne wywołania Send jak mu się to podobało. Efektem były „dzikie” dane, które odbierałem z drugiej strony.
Rozwiązanie:
int totalSend = this->Send(&msgSize, sizeof(MessageSizeType)); totalSend += this->Send(&catLength, sizeof(MessageCatLengthType)); totalSend += this->Send(category.c_str(), catLength * sizeof(wchar_t)); totalSend += this->Send(msg.c_str(), msg.length() * sizeof(wchar_t)); return totalSend;
Wniosek? Nigdy, ale to NIGDY, nie upraszczaj sobie kodu w ten sposób – lepiej dodać tą jedną zmienną, która i tak nie wprowadza żadnego narzutu i mieć pewność, że wszystko zostanie wywołane w takiej kolejności, jak być powinno, niż głowić się później „co tu jest źle”.
Dodawanie jest przemienne, a kompilator ma do tego prawo
Podobny przykład: http://www.gimpel.com/html/newbugs/bug864.htm
Ależ ja wiem, że dodawanie jest przemienne – ale jaki jest sens w tym konkretnym przypadku?
Dzięki za link.