2013-03-18 48 views
15

Mój program wykonuje typowe zadanie zapisywania danych binarnych do pliku, zgodnie z pewnym nietekstowym formatem pliku. Ponieważ dane, które piszę, nie są już w istniejących fragmentach, ale zamiast tego są łączone w bajtach w czasie wykonywania, używam std::ostream::put() zamiast write(). Zakładam, że to normalna procedura.Czy istnieje ortodoksyjny sposób uniknięcia ostrzeżenia kompilatora C4309 - "obcięcie stałej wartości" z wyjściem pliku binarnego?

Program działa dobrze. Używa zarówno std::stringstream::put() i std::ofstream::put() z dwucyfrowymi liczbami szesnastkowymi jako argumentami. Ale otrzymuję ostrzeżenie kompilatora C4309: "obcięcie stałej wartości" (w VC++ 2010), gdy argument do put() jest większy niż 0x7f. Oczywiście kompilator oczekuje wartości signed char, a stała jest poza zakresem. Ale nie sądzę, żeby faktycznie miało miejsce obcięcie; bajt zostaje zapisany tak, jak powinien.

Ostrzeżenia kompilatora sprawiają, że myślę, że nie robię rzeczy w normalny, akceptowany sposób. Sytuacja, którą opisałem, musi być powszechna. Czy istnieje typowy sposób na uniknięcie takiego ostrzeżenia kompilatora? Czy może to być przykład bezsensownego ostrzeżenia kompilatora, które powinno być po prostu ignorowane?

Pomyślałem o dwóch nieeleganckich sposobach uniknięcia tego. Podczas każdego połączenia mógłbym używać składni takiej jak mystream.put(char(0xa4)). Lub zamiast używać std::stringstream mógłbym użyć std::basic_stringstream< unsigned char >, ale nie sądzę, aby ta sztuczka działała z std::ofstream, która nie jest typem szablonowym. Wydaje mi się, że powinno być tu lepsze rozwiązanie, zwłaszcza, że ​​ofstream jest przeznaczony do pisania plików binarnych.

Twoje myśli?

--EDIT--

Ach, myliłem o std::ofstream nie jest to typ matrycy. W rzeczywistości jest to std::basic_ofstream<char>, ale próbowałem tej metody i zdałem sobie sprawę, że to nie zadziała z powodu braku zdefiniowanych metod i polimorficznej niezgodności z std::ostream.

Oto przykładowy kod:

stringstream ss; 
int a, b; 
/* Do stuff */ 
ss.put(0); 
ss.put(0x90 | a); // oddly, no warning here... 
ss.put(b);  // ...or here 
ss.put(0xa4);  // C4309 
+4

Tylko dlatego, że wszystko jasne, czy możesz dodać konkretny przykład kodu do swojego pytania? –

+1

Jestem prawie pewien, że twórcy kompilatorów nie mają czasu na generowanie "bezsensownych" ostrzeżeń. –

Odpowiedz

17

znalazłem rozwiązanie, że jestem zadowolony. Jest bardziej elegancki niż jawnie rzutowanie każdej stałej na unsigned char. To co miałem:

ss.put(0xa4); // C4309 

Myślałem, że „obcięcie” dzieje się w sposób dorozumiany odlewania unsigned char do char, ale Cong Xu wskazał, że całkowitą stałe są z założenia ma być podpisane, a ktoś większy niż 0x7f dostaje awansował z char na int. Następnie musi zostać przycięty (skrócony do jednego bajtu), jeśli zostanie przekazany do put().Używając sufiksu "u", mogę określić stałą całkowitą bez znaku, a jeśli nie jest ona większa niż 0xff, będzie to unsigned char. Oto, co mam teraz, bez ostrzeżeń kompilatora:

ss.put(0xa4u); 
7
std::stringstream ss; 
ss.put(0x7f); 
ss.put(0x80); //C4309 

Jak zgadłeś, problemem jest to, że ostream.put() oczekuje char, ale 0x7F to maksymalna wartość dla char i cokolwiek większa awansuje do int . oddasz do unsigned char, który jest tak szeroki, jak char więc przechowywać niczego char robi i bezpiecznie, ale również ostrzeżenia obcinania uzasadniony:

ss.put(static_cast<unsigned char>(0x80)); // OK 
ss.put(static_cast<unsigned char>(0xFFFF)); //C4309 
+1

Dlaczego używasz 'ss.put (static_cast (0x80));' zamiast 'ss.put (unsigned char (0x80))' lub 'ss.put ((unsigned char) 0x80)'? Czy z jakiegoś powodu preferowany jest rzut statyczny? –

+1

@SamKauffman, to tylko współczesny sposób wykonywania obsady w C++. Jest bardziej wyrazisty, ale mniej niejednoznaczny i bezpieczniejszy. –

+0

@CongXu, dzięki! To, co napisałeś o promocji, pomogło mi zrozumieć, o co tak naprawdę chodzi. –