Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Rzutowanie sprawdzające zakresy

4 views
Skip to first unread message

Piotr Wyderski

unread,
Jan 22, 2007, 6:17:47 AM1/22/07
to
Witam,

czy w boost jest jakieś gotowe rzutowanie dynamicznie
sprawdzające zakresy przy konwersji między typami
całkowitymi? Np.:

unsigned int u = safe_cast<unsigned int>(-1);

powinno rzucić wyjątkiem std::runtime_error lub
czymś podobnym. Napisanie tego porządnie samemu
to kilka godzin pracy, więc wolałbym gotowca. :-)

Pozdrawiam
Piotr Wyderski

Seweryn Habdank-Wojewódzki

unread,
Jan 22, 2007, 6:46:56 AM1/22/07
to
Witam

Piotr Wyderski wrote:

> czy w boost jest jakieś gotowe rzutowanie dynamicznie
> sprawdzające zakresy przy konwersji między typami
> całkowitymi? Np.:

A niemożesz użyć czegoś jak na stronach poniżej, aby typ był po prostu
bezpieczny?

http://www.msobczak.com/prog/bin/range.tar.gz
http://www.msobczak.com/prog/typegen/

Pozdrawiam.

--
|\/\/|   Seweryn Habdank-Wojewódzki
`\/\/'

Piotr Wyderski

unread,
Jan 22, 2007, 8:39:31 AM1/22/07
to
Seweryn Habdank-Wojewódzki wrote:

> A niemożesz użyć czegoś jak na stronach poniżej, aby typ był po prostu
> bezpieczny?

Niestety nie, dostosowuję istniejący kod.

Pozdrawiam
Piotr Wyderski

Maciej Sobczak

unread,
Jan 22, 2007, 8:43:50 AM1/22/07
to
Piotr Wyderski wrote:

>> A niemożesz użyć czegoś jak na stronach poniżej, aby typ był po prostu
>> bezpieczny?
>
> Niestety nie, dostosowuję istniejący kod.

Zgadzam się, że coś takiego (safe_cast albo może lepiej numeric_cast) by
się przydało.
Wrzuć ten temat na boost-devel, jutro Ci ktoś napisze. ;-)

--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/

Piotr Wyderski

unread,
Jan 22, 2007, 10:50:31 AM1/22/07
to
Maciej Sobczak wrote:

> Zgadzam się, że coś takiego (safe_cast albo może lepiej numeric_cast) by
> się przydało.
> Wrzuć ten temat na boost-devel, jutro Ci ktoś napisze. ;-)

:-)

Już sam zacząłem to robić. Myślałem, że jest jakiś gotowiec
w boost, bo rzecz nie wygląda na nietypową, ale skoro go
nie ma, to z przyjemnościa go napiszę. Swoją drogą, to
implementacja robi się bardziej skomplikowana niż się
pierwotnie wydawało.

Pozdrawiam
Piotr Wyderski

BobyX

unread,
Jan 22, 2007, 3:01:28 PM1/22/07
to
"Piotr Wyderski" <wyde...@ii.uni.wroc.pl> wrote:

Dla typów wbudowanych nie jest takie skomplikowane, dla pozostałych (z
operatorem konwersji) chyba nie ma sensu sprawdzać...
Moja propozycja wygląda tak:

#include <limits>
#include <stdexcept>

template <int N>
struct Int2Type {
enum { value = N };
};

namespace detail {
template <typename TargetType, typename SourceType>
inline TargetType numeric_cast(const SourceType& in, Int2Type<true>)
{
if ( in > std::numeric_limits<TargetType>::max() ||
in < std::numeric_limits<TargetType>::min())
{
throw std::runtime_error("bad numeric cast");
}

return in;
}

template <typename TargetType, typename SourceType>
inline TargetType numeric_cast(const SourceType& in, Int2Type<false>)
{
return in;
}
} //namespace

template <typename TargetType, typename SourceType>
inline TargetType numeric_cast(const SourceType& in)
{
detail::numeric_cast<TargetType>(in,
Int2Type<std::numeric_limits<SourceType>::is_specialized
&& std::numeric_limits<TargetType>::is_specialized>());
}

Pozdrawiam,
BX

Maciej Sobczak

unread,
Jan 23, 2007, 8:44:09 AM1/23/07
to
BobyX wrote:

> Moja propozycja wygląda tak:

> if ( in > std::numeric_limits<TargetType>::max() ||
> in < std::numeric_limits<TargetType>::min())

Nie zadziała gdy typ źródłowy jest signed a drugi unsigned i gdy in
będzie poza zakresem tego drugiego, bo na skutek konwersji zostanie
przeinterpretowany bit znaku.

#include <iostream>
#include <limits>
int main()
{
int in = -7;
if (in > std::numeric_limits<unsigned int>::max() ||
in < std::numeric_limits<unsigned int>::min())
{
std::cout << "Shit, " << in
<< " is out of unsigned int!\n";
}
else
{
std::cout << "OK and cool, " << in
<< " fits into unsigned int.\n";
}
}

$ ./a.out
OK and cool, -7 fits into unsigned int.
$

To nie jest takie hop-siup. :-)

Seweryn Habdank-Wojewódzki

unread,
Jan 23, 2007, 10:40:04 AM1/23/07
to
Witam

Maciej Sobczak wrote:

> Nie zadziała gdy typ źródłowy jest signed a drugi unsigned i gdy in
> będzie poza zakresem tego drugiego, bo na skutek konwersji zostanie
> przeinterpretowany bit znaku.

A nie można tak po prostu napisać makro generujące wszystkie specjalizacje
dla typów signed i unsigned?

Albo jakoś dynamicznie sprawdzać czy typ jest signed czy unsigend. Kiedyś
była dyskusja o endiannes i nagle okazało się że to jest pikuś, może z
signed i unsigned też jest banał. Powinno to wyjść poprzez test czy rzut
(-1) na typ jest dalej (-1) albo czy jest < 0, albo jakiś przygłupawy w
każdym razie np. (type)(-1) > 2 * 1, czy nie?

Piotr Wyderski

unread,
Jan 23, 2007, 11:10:53 AM1/23/07
to
Seweryn Habdank-Wojewódzki wrote:

> A nie można tak po prostu napisać makro generujące wszystkie specjalizacje
> dla typów signed i unsigned?

Sporo ich będzie.

> Albo jakoś dynamicznie sprawdzać czy typ jest signed czy unsigend.

Przecież z łatwością da się ro sprawdzić statycznie.
W numeric_limits masz składową is_signed.

> może z signed i unsigned też jest banał.

Bo to koncepcyjnie jest banał, tylko implementacja jest dość żmudna.
Trzeba zadbać o właściwe konwersje między typami z i bez znaku,
nie sprawdzać min() i max() tam, gdzie tego nie trzeba (co już daje 8
specjalizacji), dodać warianty do konwersji z i na bool itd.

Ja się nie pytałem o to, jak to zrobić, bo to wiem, tylko czy istnieje
gotowiec. Ale wygląda na to, że go nie ma, więc czeka mnie trochę
własnoręcznej rzeźby. :-)

Pozdrawiam
Piotr Wyderski

Seweryn Habdank-Wojewódzki

unread,
Jan 23, 2007, 12:31:12 PM1/23/07
to
Witam

Piotr Wyderski wrote:

> Ja się nie pytałem o to, jak to zrobić, bo to wiem, tylko czy istnieje
> gotowiec. Ale wygląda na to, że go nie ma, więc czeka mnie trochę
> własnoręcznej rzeźby. :-)

Rozumiem. Ale sugeruję, że to będzie sprawa napisania stosownego makra oraz
może szablonu w C++. Oraz w najgorszym przypadku w pythonie generatora
kodu, aby wypełnić macierz konwersji typów i zapakować to do jednego
headera.

Nie przyglądałem się, jak napisać najzgrabniej taki kawałek kodu, ale wydaje
mi się, że po napisaniu jednej dwóch konwersji to jest będzie arcycepowate
rozwiązanie. Więc można napisać sobie generator kodu. Nawet nie bedziesz
się musiał wiele napisać. Typów standardowych jest niewiele. Typów
windowsa, jest trochę. Linuxa nie używasz, więc olewasz typy standardowe w
linuxie :-D.

Piotr Wyderski

unread,
Jan 23, 2007, 12:53:32 PM1/23/07
to
Seweryn Habdank-Wojewódzki wrote:

> Nie przyglądałem się, jak napisać najzgrabniej taki kawałek kodu

Mnie zajęło to 239 linii, ale sport część tego to specjalna
obsługa booli oraz furtki dla przyszłych rozszerzeń.

> Linuxa nie używasz

Nie używam jako ceniący sobie wygodę user, ale jako programista używam. ;-)

Pozdrawiam
Piotr Wyderski

Seweryn Habdank-Wojewódzki

unread,
Jan 23, 2007, 4:59:12 PM1/23/07
to
Witam

Piotr Wyderski wrote:

> Mnie zajęło to 239 linii, ale sport część tego to specjalna
> obsługa booli oraz furtki dla przyszłych rozszerzeń.

A tak przy okazji, znalazłem pole w numeric_limits<T>::is_signed, czy ono
nie daje odpowiedzi na to pytanie?

BobyX

unread,
Jan 23, 2007, 6:20:26 PM1/23/07
to
"Maciej Sobczak" <no....@no.spam.com> wrote

> BobyX wrote:
>> Moja propozycja wygląda tak:
>
>> if ( in > std::numeric_limits<TargetType>::max() ||
>> in < std::numeric_limits<TargetType>::min())
>
> Nie zadziała gdy typ źródłowy jest signed a drugi unsigned i gdy in będzie
> poza zakresem tego drugiego, bo na skutek konwersji zostanie
> przeinterpretowany bit znaku.

> To nie jest takie hop-siup. :-)

...faktycznie, trzeba obsłużyć jeszcze pare przypadków

For every complex problem, there is a solution that is simple, neat, and
wrong : )

Pozdrawiam
BX

Piotr Wyderski

unread,
Jan 24, 2007, 5:20:21 AM1/24/07
to
Seweryn Habdank-Wojewódzki wrote:

> A tak przy okazji, znalazłem pole w numeric_limits<T>::is_signed, czy ono
> nie daje odpowiedzi na to pytanie?

Ale na jakie pytanie? :-D

Pozdrawiam
Piotr Wyderski

Seweryn Habdank-Wojewódzki

unread,
Jan 24, 2007, 6:25:07 AM1/24/07
to
Witam

Piotr Wyderski wrote:

> Seweryn Habdank-Wojewódzki wrote:
>
>> A tak przy okazji, znalazłem pole w numeric_limits<T>::is_signed, czy ono
>> nie daje odpowiedzi na to pytanie?
>
> Ale na jakie pytanie? :-D

BobyX napisał szablon, który kontroluje zakresy. A skolei Maciek podnios
problem signed i unsigned. I tu znowu można zrobić specjalizację szablonu
kiedy jest zgodność, signed albo unsigned typów. A kiedy nie ma to trzeba
zawężać zakres, tak aby:

int a=-1
unsigbed int b = numeric_cast<int>(a);

sypnęło wyjątkiem.

Maciej Sobczak

unread,
Jan 24, 2007, 8:42:06 AM1/24/07
to
Seweryn Habdank-Wojewódzki wrote:

> int a=-1
> unsigbed int b = numeric_cast<int>(a);
>
> sypnęło wyjątkiem.

Niestety to akurat nie sypnie - zapomniałeś unsigned w numeric_cast,
dzięki czemu numeric_cast nie robi nic a problem sprowadzi się ponownie
do standardowej konwersji. To właśnie pokazuje, że ten schemat jest
zbudowany na słabych fundamentach.

Niestety, ale dymyślne konswersje dla typów wbudowanych są zwalone.
Jeżeli już ktoś i tak musi się tymi typami posługiwać, to może liczyć co
najwyżej na warningi od kompilatora.

Seweryn Habdank-Wojewódzki

unread,
Jan 24, 2007, 10:14:09 AM1/24/07
to
Witam

Maciej Sobczak wrote:

> Niestety to akurat nie sypnie - zapomniałeś unsigned w numeric_cast,

Tak. poprawiam się,

int a=-1
unsigbed int b = numeric_cast<unsigned int>(a);

Dla podkreślenia. Mam na myśli konkretyzację:

numeric_cast<unsigned int>( int a ).

Powinno sypnąć, prawda? To znaczy istnieje implementacja taka
numeric_cast<T>(), która powinna sypnąć wyjątkiem.

Czy ja czegoś nie rozumiem?

> Niestety, ale dymyślne konswersje dla typów wbudowanych są zwalone.
> Jeżeli już ktoś i tak musi się tymi typami posługiwać, to może liczyć co
> najwyżej na warningi od kompilatora.

Tak. Ja akurat jestem w tej dobrej sytuacji, że sypie mi warningami.

Sektor van Skijlen

unread,
Jan 24, 2007, 5:17:43 PM1/24/07
to
Dnia Tue, 23 Jan 2007 16:40:04 +0100, Seweryn Habdank-Wojewódzki skrobie:
> Witam

> Maciej Sobczak wrote:

> > Nie zadziała gdy typ źródłowy jest signed a drugi unsigned i gdy in
> > będzie poza zakresem tego drugiego, bo na skutek konwersji zostanie
> > przeinterpretowany bit znaku.

> A nie można tak po prostu napisać makro generujące wszystkie specjalizacje
> dla typów signed i unsigned?

A nie można po prostu napisać jednego wzorca, który na podstawie typu podanego
argumentu pobierze z niego std::numeric_limits?

> Albo jakoś dynamicznie sprawdzać czy typ jest signed czy unsigend.

Po pierwsze, dynamicznie tego się nie da sprawdzić - jak wartość unsigned int
przypisałeś do zmiennej signed int to już jest dawno po ogórkach.

Po drugie, nie ma po co sprawdzać dynamicznie, skoro ten typ jest znany w
czasie kompilacji. Jeśli nie - to patrz linijka wyżej.

--
// _ ___ Michal "Sektor" Malecki <sektor(whirl)kis.p.lodz.pl>
\\ L_ |/ `| /^\ ,() <ethouris(O)gmail.com>
// \_ |\ \/ \_/ /\ C++ bez cholesterolu: http://www.intercon.pl/~sektor/cbx
"Java is answer for a question that has never been stated"

Seweryn Habdank-Wojewódzki

unread,
Jan 25, 2007, 3:21:45 AM1/25/07
to
Witam

Sektor van Skijlen wrote:

> A nie można po prostu napisać jednego wzorca, który na podstawie typu
> podanego argumentu pobierze z niego std::numeric_limits?

Więc właśnie tego nie kapuję.

zgrubsza chodzi o sytuację jak dla int:

int = numeric_cast<int>( /* unsigned long */ x )

tak, żeby słał wyjątki kiedy x < 0 [czyli numeric_limits<unsigned
long>::min()] oraz kiedy x > numeric_limits<int>::max();

Sztuka polega, na tym aby to jakoś zgrabnie zapiąć w szablon jeszcze nie
czuję sprawy, ale jakby szablon mógł rozwijać wyrażenie (exp ? expr1 :
expr2) to powinno nie być trudne, bo wystarczy jako ograniczenie dolne
wybrać

lower_bound = max ( min_type_1, min_type_2 )
upper_bound = min ( max_type_1, max_type_2 )

I koniec, chodzi o to, aby to byo znane w czasie kompilacji, bo bezsęsu to
robić w runtime, kiedy i tak nie ma się wpływu na granice POD w runtime.

Sektor van Skijlen

unread,
Jan 25, 2007, 9:37:33 AM1/25/07
to
Dnia Thu, 25 Jan 2007 09:21:45 +0100, Seweryn Habdank-Wojewódzki skrobie:
> Witam

> Sektor van Skijlen wrote:

> > A nie można po prostu napisać jednego wzorca, który na podstawie typu
> > podanego argumentu pobierze z niego std::numeric_limits?

> Więc właśnie tego nie kapuję.

> zgrubsza chodzi o sytuację jak dla int:

> int = numeric_cast<int>( /* unsigned long */ x )

> tak, żeby słał wyjątki kiedy x < 0 [czyli numeric_limits<unsigned
> long>::min()] oraz kiedy x > numeric_limits<int>::max();

template <class Target, class Source>
Target numeric_cast( Source x )
{
if ( std::numeric_limits<Source ...
}

Nie kończę, bo to wymaga pomyślunku, jak napisałeś niżej, a w tej chwili mi
się nie chce :)

> Sztuka polega, na tym aby to jakoś zgrabnie zapiąć w szablon jeszcze nie
> czuję sprawy, ale jakby szablon mógł rozwijać wyrażenie (exp ? expr1 :
> expr2) to powinno nie być trudne, bo wystarczy jako ograniczenie dolne
> wybrać

> lower_bound = max ( min_type_1, min_type_2 )
> upper_bound = min ( max_type_1, max_type_2 )

W zasadzie to masz tak:
1. Załóżmy, że masz pewność, iż wartość w typie źródłowym mieści się w
numeric_limits
2. Teraz trzeba sprawdzić, czy wartość źródłowa "mieściłaby się" w
numeric_limits typu docelowego
3. W tym celu potrzebujemy mieć zakresy dla typu docelowego przekonwertowane
na wartości typu źródłowego :)

I tu niestety klapa. Chociaż, gdyby się temu uważniej przyjrzeć, to nie jest
jeszcze tak źle. Pierwsza rzecz, jaką musisz sprawdzić, to is_signed. I wtedy:

- jeśli mają taką samą signedness, to musisz sprawdzić "na szerokość"
- jeśli tylko typ docelowy jest unsigned, to zamiast dolnego zakresu
sprawdzasz, czy wartość źródłowa nie jest ujemna
- jeśli typ źródłowy jest unsigned do w ogóle nie sprawdzasz dolnego zakresu

To jest trochę ekwilibrystyka, niestety, właśnie dlatego, że nie możesz
bezpośrednio przekonwertować zakresów dla wartości docelowej na typ źródłowy,
bo jakby to było takie proste, to mógłbyś w ogóle konwertować bez sprawdzania
zakresów. Konwersja wartości zakresów jest niestety obarczona tym samym
ryzykiem co konwersja interesującej nas wartości.

> I koniec, chodzi o to, aby to byo znane w czasie kompilacji, bo bezsęsu to
> robić w runtime, kiedy i tak nie ma się wpływu na granice POD w runtime.

No to czeka cię jeszcze lepsza ekwilibrystyka z metaprogramowaniem (różne
specjalizacje dla typów różnej szerokości) - ale jest to wykonalne.

Maciej Sobczak

unread,
Jan 26, 2007, 2:32:09 AM1/26/07
to
Piotr Wyderski wrote:

>> A niemożesz użyć czegoś jak na stronach poniżej, aby typ był po prostu
>> bezpieczny?
>
> Niestety nie, dostosowuję istniejący kod.

Czytam te wszystkie posty i się dziwię. Co to znaczy - dostosowuję
istniejący kod? Wstawiasz numeric_cast gdzie popadnie?
Czy nie prościej zrobić (albo wygenerować) wrappery do użytych typów i
zmodyfikować tylko deklaracje zmiennych zamiast modyfikować wszystkie
wyrażenia?
Obstawiam, że deklaracji jest mniej i łatwiej je znaleźć, niż wszystkie
miejsca niejawnych konwersji.

Piotr Wyderski

unread,
Jan 26, 2007, 5:59:08 AM1/26/07
to
Maciej Sobczak wrote:

> Czytam te wszystkie posty i się dziwię.

Nie dziwię się, że się dziwisz. :-)

> Co to znaczy - dostosowuję istniejący kod?

Taki z asercjami sizeof(std::size_t) == sizeof(uint32_t)... :-/

> Czy nie prościej zrobić (albo wygenerować) wrappery do użytych typów i
> zmodyfikować tylko deklaracje zmiennych zamiast modyfikować wszystkie
> wyrażenia?

Nie, bo musi zostać zachowana spójność na poziomie serializacji.

Pozdrawiam
Piotr Wyderski

Piotr Wyderski

unread,
Jan 27, 2007, 3:16:26 PM1/27/07
to
Maciej Sobczak wrote:

> Niestety, ale dymyślne konswersje dla typów wbudowanych są zwalone.

Powiedziałbym nawet, że to same typy wbudowane są
zwalone, ale nie chce mi się odgrzewać starych flejmów.

No, może jednak odrobinkę: co stoi na przeszkodzie
dodania przez Komitet do standardu języka appendixu
doprecyzowującego semantykę większości UB? Widzę
to tak: główny standard języka rozwija się jak dotychczas,
po staremu wszelkimi sposobami wymykając się jak
piskorz od udzielenia odpowiedzi na pytania "co to jest
int? ile ma bitów, jakie kodowanie?, co się stanie, gdy
do INT_MAX dodam 1?" i tysiące innych, natomiast
załącznik na podstawie dekad rozwoju hardware dokładnie
określa brzmienie odpowiedzi, jak to ma miejsce w Javie
i C#. Dzięki temu można jednocześnie mieć ciastko i zjeść
ciastko -- przed rozpoczęciem prac nad nowym projektem
podejmie się decyzję, z gwarancji której części standardu
korzystamy i wszyscy będą zadowoleni. Puryści i fanatycy
starego ładu (bo i tacy się pojawią :-)) będą mogli pisać
tak, jak to robili do tej pory, a pragmatycy będą mogli
spać spokojnie, bez zrywania się z krzykiem, że przyśniły
im się się niedostatecznie pojemne liczby całkowite,
awaryjne zatrzymanie biegu programu z powodu przepełnienia
numerycznego, operacji logicznych na wskaźnikach itd.
Sam C++ na tym nic nie straci, bo UB dopuszczalne
zachowanie, a więc między innymi _takie_, jak w załączniku.
W nagłówkach wymagających większych gwarancji dopisze
się po prostu

#pragma common_sense_cplusplus

i będzie się można cieszyć się zdeubekizowanym dialektem języka...
Jeśli zaś się tego nie dopisze, to semantyka delikatnych konstrukcji
będzie taka, jak dawniej, a więc właściwie jej nie będzie.

> Jeżeli już ktoś i tak musi się tymi typami posługiwać, to może liczyć co
> najwyżej na warningi od kompilatora.

Ostrożnie, ta sprawa jest bardzo delikatna i nie da się jej zbyć
jednym zdaniem komentarza. Nie masz wpływu m.in. na definicję
std::vector<T>::size_type. Chcąc wprowadzić możliwość wymiany
danych pomiędzy wersjami tego samego programu skompilowanymi
jako 32- i 64-bitowe pojawia się spory problem, bo w jaki sposób
deserializować size_t? Można przyciąć do uint32_t, ale wówczas
pojawia się możliwość, że 64-bitowy wektor zawiera 2^32+ elementów
i dostaniemy przepełnienie. Można też rozszerzyć do uint64_t, ale
dlaczego akurat do tego typu? A co, jeśli ktoś zrobi porting na
maszynę 128-bitową? -- 2^64 elementów znów się nie zmieści.
Teoretyczie najlepszym rozwiązaniem będzie użycie liczb całkowitych
wielokrotnej precyzji, ale wówczas komunikacja będzie działać
z prędkością warpową i masz spore szanse, że o zmroku do Twoich
drzwi zastuka tłum uzbrojonych w widły i pochodnie użytkowników
Twojej biblioteki. Cóż, jak nie urok, to... :-)

Pozdrawiam
Piotr Wyderski

Maciej Sobczak

unread,
Jan 29, 2007, 3:06:39 AM1/29/07
to
Piotr Wyderski wrote:

>> Co to znaczy - dostosowuję istniejący kod?
>
> Taki z asercjami sizeof(std::size_t) == sizeof(uint32_t)... :-/

Da się.

>> Czy nie prościej zrobić (albo wygenerować) wrappery do użytych typów i
>> zmodyfikować tylko deklaracje zmiennych zamiast modyfikować wszystkie
>> wyrażenia?
>
> Nie, bo musi zostać zachowana spójność na poziomie serializacji.

Zrób wrapperek jako PODa, gdzie T będzie jedynym polem.

Maciej Sobczak

unread,
Jan 29, 2007, 3:34:11 AM1/29/07
to
Piotr Wyderski wrote:

> Powiedziałbym nawet, że to same typy wbudowane są
> zwalone, ale nie chce mi się odgrzewać starych flejmów.

Eeee, typy wbydowane nie są tragiczne. To ich wzajemne relacje i
interakcje czynią je słabymi.

> No, może jednak odrobinkę: co stoi na przeszkodzie
> dodania przez Komitet do standardu języka appendixu
> doprecyzowującego semantykę większości UB?

Producenci kompilatorów to robią. Mogą.

> Widzę
> to tak: główny standard języka rozwija się jak dotychczas,
> po staremu wszelkimi sposobami wymykając się jak
> piskorz od udzielenia odpowiedzi na pytania "co to jest
> int? ile ma bitów, jakie kodowanie?, co się stanie, gdy
> do INT_MAX dodam 1?"

Standard ma zastosowanie do różnych sprzętów, również tych
bezsensownych. Normalni ludzi jednak piszą na jakiś podzbiór platform,
gdzie ich architektura podaje brakujące odpowiedzi.

> natomiast
> załącznik na podstawie dekad rozwoju hardware dokładnie
> określa brzmienie odpowiedzi, jak to ma miejsce w Javie
> i C#.

Java i C# są tak nieprzenośne, że z podobnym efektem można skoncentrować
się na jednym kompilatorze C++, który też udziela jasnych odpowiedzi na
Twoje pytania.

> Dzięki temu można jednocześnie mieć ciastko i zjeść
> ciastko -- przed rozpoczęciem prac nad nowym projektem
> podejmie się decyzję, z gwarancji której części standardu
> korzystamy i wszyscy będą zadowoleni.

Korzystamy z tych gwarancji, które dają nam kompilatory.
Oprócz "Hello World" robią tak chyba wszystkie programy.

> Puryści i fanatycy
> starego ładu (bo i tacy się pojawią :-)) będą mogli pisać
> tak, jak to robili do tej pory, a pragmatycy będą mogli
> spać spokojnie, bez zrywania się z krzykiem, że przyśniły
> im się się niedostatecznie pojemne liczby całkowite,
> awaryjne zatrzymanie biegu programu z powodu przepełnienia
> numerycznego, operacji logicznych na wskaźnikach itd.

Obudziłeś się kiedyś z tego powodu? Ja nie. :-)

>> Jeżeli już ktoś i tak musi się tymi typami posługiwać, to może liczyć
>> co najwyżej na warningi od kompilatora.
>
> Ostrożnie, ta sprawa jest bardzo delikatna i nie da się jej zbyć
> jednym zdaniem komentarza. Nie masz wpływu m.in. na definicję
> std::vector<T>::size_type. Chcąc wprowadzić możliwość wymiany
> danych pomiędzy wersjami tego samego programu skompilowanymi
> jako 32- i 64-bitowe pojawia się spory problem, bo w jaki sposób
> deserializować size_t?

Tekstowo. XML jest modny ostatnio. Albo binarnie, używając
jakiegokolwiek standardu (XDR, ASN.1).

BTW - jak sobie radzisz z serializacją pomiędzy Javą i C#? :-P

> Teoretyczie najlepszym rozwiązaniem będzie użycie liczb całkowitych
> wielokrotnej precyzji, ale wówczas komunikacja będzie działać
> z prędkością warpową

Serializacja nie jest tutaj ograniczeniem prędkości. Jeżeli podajesz już
przykłady wektorów z 128-bitowym rozmiarem, to na moje oko
serializowanie *jednego pola* typu size_type nie przeraża mnie w
kontekście tego wszystkiego, co musi polecieć zaraz za nim.

Jak zwykle piętrzysz problemy. :-)

Piotr Wyderski

unread,
Jan 29, 2007, 6:05:37 AM1/29/07
to
Maciej Sobczak wrote:

>> No, może jednak odrobinkę: co stoi na przeszkodzie
>> dodania przez Komitet do standardu języka appendixu
>> doprecyzowującego semantykę większości UB?
>
> Producenci kompilatorów to robią. Mogą.

Ale te dodatki obowiązują tylko w obrębie danego kompilatora,
a tymczasem ja chcę mieć program przenośny, choć korzystający
ze znacznie silniejszych gwarancji, niż dotychczasowe. Efektem
będzie oczywiście mniejsza liczba platform docelowych, ale
w praktyce kompletnie nie ma to znaczenia, bo bezsensowne
platformy i tak są na wymarciu.

> Standard ma zastosowanie do różnych sprzętów, również tych bezsensownych.

I właśnie o to chodzi, by dalej sobie miał. Jedynie na
platformach sensownych dojdzie pewien zbiór dodatkowych
gwarancji. Skorzystanie z nich będzie dobrowolne, choć
nie mam wątpliwości, co wybierze przemysł. :-)

> Normalni ludzi jednak piszą na jakiś podzbiór platform, gdzie ich
> architektura podaje brakujące odpowiedzi.

Dokładnie o to chodzi. Więc należy dać im te gwarancje,
bo i tak się nic na tym nie traci. Podkreślam, chodzi o
dołączenie do standardu rozdziału dającego dodatkowe
gwarancje dla osób gotowych zrezygnować z "dziwnych"
platform, a nie o przedefiniowanie pozostałej części standardu.
Właśnie na tym polega sztuczka. :-)

> Java i C# są tak nieprzenośne

Jasne, zwłaszcza ta pierwsza...

> Korzystamy z tych gwarancji, które dają nam kompilatory.

... w obrębie danego kompilatora.

> Oprócz "Hello World" robią tak chyba wszystkie programy.

Robią, bo muszą, stąd setki headerów z #ifdefami...

> Tekstowo. XML jest modny ostatnio.

Ale nie o reprezentację chodzi, tylko o to, do jakiego typu
deserializować zapisaną wartość i co zrobić, jeśli przekracza
pojemność żądanego typu docelowego (np. std::size_t).

> BTW - jak sobie radzisz z serializacją pomiędzy Javą i C#? :-P

Mapuję typy C++ na typy javowe i działa bez pudła?

> Serializacja nie jest tutaj ograniczeniem prędkości.

Może być.

> Jeżeli podajesz już przykłady wektorów z 128-bitowym rozmiarem,
> to na moje oko serializowanie *jednego pola* typu size_type nie przeraża
> mnie w kontekście tego wszystkiego, co musi polecieć zaraz za nim.

Nie o to chodzi. Problemem jest to, co zrobić z size_t...

Pozdrawiam
Piotr Wyderski

Jedrzej Dudkiewicz

unread,
Jan 29, 2007, 6:47:01 AM1/29/07
to
> > Jeżeli podajesz już przykłady wektorów z 128-bitowym rozmiarem,
> > to na moje oko serializowanie *jednego pola* typu size_type nie przeraża
> > mnie w kontekście tego wszystkiego, co musi polecieć zaraz za nim.
>
> Nie o to chodzi. Problemem jest to, co zrobić z size_t...

Ale przecież program, w którym vector<...>::size_t ma 32 bity i tak nie jest
w stanie przechować obiektów z drugiego wektora, w którym tych danych jest
2^32+n, n >= 1, więc w czym problem? Albo jesteś gotowy na taką ilość danych
i używasz własnej implementacji wektora, albo nie jesteś, i zgłaszasz błąd
deserializacji.

A gwarancje, o jakich pisałeś, na pewno by się przydały.

JD

Piotr Wyderski

unread,
Jan 29, 2007, 8:40:53 AM1/29/07
to
Jedrzej Dudkiewicz wrote:

> Ale przecież program, w którym vector<...>::size_t ma 32 bity i tak nie
> jest
> w stanie przechować obiektów z drugiego wektora, w którym tych danych jest
> 2^32+n, n >= 1

n >= 0, 2^32 też się nie zmieści. ;-)

> więc w czym problem?

Problem jest właśnie w ustaleniu, co jest problemem. :-)
Można przyjąć, że przy serializacji rozszerzamy size_t
do np. 64 bitów, ale wówczas wersja 32-bitowa musi
odpowiednio zareagować na tę sytuację. Można też
przyciąć size_t do 32 bitów i zapewnić, że żaden kontener
nie będzie miał więcej elementów. Wady są oczywiste,
ale zaletą jest bliższe naśladowanie interfejsu Javy, która
używa typu int do określania rozmiaru kolekcji.

> A gwarancje, o jakich pisałeś, na pewno by się przydały.

I da się je wprowadzić bez rewolucji, której zwolennikiem byłem wcześniej.
:-)
Suplement do standardu w postaci opcjonalnie wykorzystywanego załącznika
idealnie załątwia sprawę.

Pozdrawiam
Piotr Wyderski

Maciej Sobczak

unread,
Jan 29, 2007, 8:45:01 AM1/29/07
to
Piotr Wyderski wrote:

>> Producenci kompilatorów to robią. Mogą.
>
> Ale te dodatki obowiązują tylko w obrębie danego kompilatora

Albo w obrębie wielu kompilatorów, które dają takie same gwarancje. W
czym problem?

>> Standard ma zastosowanie do różnych sprzętów, również tych bezsensownych.
>
> I właśnie o to chodzi, by dalej sobie miał. Jedynie na
> platformach sensownych dojdzie pewien zbiór dodatkowych
> gwarancji. Skorzystanie z nich będzie dobrowolne, choć
> nie mam wątpliwości, co wybierze przemysł. :-)

No przecież przemysł wybiera - wszystkie znane mi kompilatory dają
zgodne gwarancje w większości interesujących mnie obszarów.

> Podkreślam, chodzi o
> dołączenie do standardu rozdziału dającego dodatkowe
> gwarancje dla osób gotowych zrezygnować z "dziwnych"
> platform, a nie o przedefiniowanie pozostałej części standardu.
> Właśnie na tym polega sztuczka. :-)

To po co to wstawiać do standardu? Zrób sobie osobny dokument pt.
"Recommendations for implementers of the C++ programming language for
platform X, Y and Z".
Zdaje się, że Intel nawet coś takiego popełnił.

>> Java i C# są tak nieprzenośne
>
> Jasne, zwłaszcza ta pierwsza...

Zwłaszcza ta pierwsza nie działa na żadnym z tysiąca komputerów, którymi
się zajmuje moja grupa w pracy. Już ten temat przerabialiśmy.

>> Korzystamy z tych gwarancji, które dają nam kompilatory.
>
> ... w obrębie danego kompilatora.

W obrębie wielu kompilatorów.

>> Oprócz "Hello World" robią tak chyba wszystkie programy.
>
> Robią, bo muszą, stąd setki headerów z #ifdefami...

Z mojej skromnej praktyki wynika, że #ifdefy rozwiązują głównie problem
niezgodności między systemami operacyjnymi, nawet jeśli sprzęt pod nimi
jest ten sam. To jest shit, ale nie ja go wymyśliłem.

Chociaż faktem jest też, że np. kod Boosta ma masę omijaczy na różne
kompilatory - ale to dotyczy raczej bugów w kompilatorach a nie
gwarancji dla typów podstawowych (a o tym mowa).

>> Tekstowo. XML jest modny ostatnio.
>
> Ale nie o reprezentację chodzi, tylko o to, do jakiego typu
> deserializować zapisaną wartość i co zrobić, jeśli przekracza
> pojemność żądanego typu docelowego (np. std::size_t).

To i tak jesteś w błocie. Nie ma znaczenia, czy sobie wymyślisz własny
typ na tą okoliczność, jak np. w Adzie:

type My_Size_Type is range 0..10000000000000000000000000000000;

(co AFAIK nie musi wcale zadziałać)

bo ograniczenie *i tak* jest arbitralne po stronie odbiorcy - co
zrobisz, jeśli deserializowana wartość jest poza tym arbitralnie
wybranym zakresem?
Podobnie, std::size_t ma arbitralną wartość na kompilatorze, którego
używasz - to jest ten sam problem. Albo potrafisz przewidzieć w jakich
warunkach będzie działać Twój system, albo nie potrafisz. W tym drugim
przypadku i tak ugrzęzłeś.

>> BTW - jak sobie radzisz z serializacją pomiędzy Javą i C#? :-P
>
> Mapuję typy C++ na typy javowe i działa bez pudła?

Jakie typy C++, skoro standard nie określa ich rozmiarów? :-P

>> Jeżeli podajesz już przykłady wektorów z 128-bitowym rozmiarem,
>> to na moje oko serializowanie *jednego pola* typu size_type nie
>> przeraża mnie w kontekście tego wszystkiego, co musi polecieć zaraz za
>> nim.
>
> Nie o to chodzi. Problemem jest to, co zrobić z size_t...

Nic. Przyjmij, że std::size_t ma maksymalny rozmiar, który ma sens na
danej platformie jako ilość elementów dowolnej kolekcji (taka w zasadzie
jest intencja tego typu). Jeśli coś się w tym typie nie mieści, to tym
bardziej nie zmieści się w wektorze dana ilość elementów i nawet nie ma
po co ich deserializować. Proste.

Piotr Wyderski

unread,
Jan 29, 2007, 9:24:56 AM1/29/07
to
Maciej Sobczak wrote:

> Albo w obrębie wielu kompilatorów, które dają takie same gwarancje.

Po pierwsze wielu nie znaczy wszystkich, a po drugie gdzie
masz te _gwarancje_ i kto odpowiada za spójnośc między
poszczególnymi rekomendacjami? Nikt? Ojej...

> W czym problem?

W tym, że jeśli napiszę sobie program opierający się na takich
założeniach i poinformuję kompilator o tym odpowiednia pragmą,
to oczekuję, że albo kompilator mi taki program odrzuci w całości,
bo platforma nie pasuje lub on nie rozumie tej pragmy, albo
wygeneruje mi kod o bardzo dokładnie okreslonej semantyce.
_Dowolny_ kompilator ma to potrafić bez szemranych założeń.

> To po co to wstawiać do standardu?

Bo:

-- w bardzo istotnym stopniu dotyczy języka;
-- zmiany w standardzie będą na bieżąco synchronizowane z załącznikiem;
-- ISO ma autorytet. Kogo w przypadku C++ obchodzą rekomendację
jakiegoś tam Intela, że litościwie nie wspomnę o moich?

> Zrób sobie osobny dokument pt. "Recommendations for implementers
> of the C++ programming language for platform X, Y and Z".

Właśnie chodzi o brak tego "X, Y and Z". Chodzi o specyfikację maszyny
abstrakcyjnej C++ zgodną z dotychczasowymi gwarancjami _oraz_ ze
stanem techniki 20 lat po powstaniu C++. _Jeśli_ docelowa architektura
rzeczywista spełnia tę specyfikację _oraz jesli_ na kompilatorze wymusi
się zgodność z załącznikiem, to dostaniesz program o bardzo dokładnie
okreslonej semantyce, praktycznie bez UB. W przeciwnym razie będziesz
miał zwykłe C++.

> Zwłaszcza ta pierwsza nie działa na żadnym z tysiąca komputerów, którymi
> się zajmuje moja grupa w pracy. Już ten temat przerabialiśmy.

To musisz mieć straszengo pecha, bo zazwyczaj działa ona bez problemu.

> W obrębie wielu kompilatorów.

Na zasadzie domniemania.

> bo ograniczenie *i tak* jest arbitralne po stronie odbiorcy

Nie wszędzie -- np. w Javie pojemność kontenerów jest opisywana
typem o ustalonym zakresie, mianowicie 32-bitowym intem w U2.
Rozwiązanie ma sporo wad, ale akurat problemu z serializacją nie ma.

> Jakie typy C++, skoro standard nie określa ich rozmiarów? :-P

Na int32_t, int64_t itd. Ale fakt -- nieokreślone są nie tylko
rozmiary, ale i kodowanie liczb ze znakiem.

> Jeśli coś się w tym typie nie mieści, to tym bardziej nie zmieści
> się w wektorze dana ilość elementów i nawet nie ma po co ich
> deserializować. Proste.

I to dokładnie robię, safe_cast<> mi to sprawdza -- pytałeś, po co mi to.
:-)

Pozdrawiam
Piotr Wyderski

SasQ

unread,
Jan 29, 2007, 1:53:12 PM1/29/07
to
Dnia Mon, 29 Jan 2007 15:24:56 +0100, Piotr Wyderski napisał(a):

>> Zwłaszcza ta pierwsza nie działa na żadnym z tysiąca
>> komputerów, którymi się zajmuje moja grupa w pracy.
>

> To musisz mieć straszengo pecha, bo zazwyczaj działa
> ona bez problemu.

Z bash.org [tłumaczenie własne]:
"Mówienie, że Java jest fajna, bo działa na wszystkich
platformach, to jak mówienie, że seks analny jest fajny,
bo działa na wszystkich płciach" ;J

--
SasQ

Maciej Sobczak

unread,
Jan 30, 2007, 3:00:23 AM1/30/07
to
SasQ wrote:

>>> Zwłaszcza ta pierwsza nie działa na żadnym z tysiąca
>>> komputerów, którymi się zajmuje moja grupa w pracy.
>> To musisz mieć straszengo pecha, bo zazwyczaj działa
>> ona bez problemu.

Zazwyczaj to nawet na FreeBSD nie działa i trzeba używać nieoficjalnie
zhaczonych binarek.
A jak się ma pecha, to jest LynxOS. Nie, nie możemy sobie zmienić.

> Z bash.org [tłumaczenie własne]:
> "Mówienie, że Java jest fajna, bo działa na wszystkich
> platformach, to jak mówienie, że seks analny jest fajny,
> bo działa na wszystkich płciach" ;J

Aż sobie to zapisałem. :D

Piotr Wyderski

unread,
Jan 30, 2007, 6:11:57 AM1/30/07
to
SasQ wrote:

> "Mówienie, że Java jest fajna, bo działa na wszystkich
> platformach, to jak mówienie, że seks analny jest fajny,
> bo działa na wszystkich płciach" ;J

No ale C++ szczyci się tym, że ze względu na znacznie mniej
ograniczeń nakładanych na sprzęt działa na jeszcze większej
liczbie platform, niż Java, która jest "wszędzie". O co więc
w jego przypadku należy rozszerzyć powyższą "myśl", o
zwierzęta? :-)

Pozdrawiam
Piotr Wyderski

Jedrzej Dudkiewicz

unread,
Jan 30, 2007, 6:25:08 AM1/30/07
to

W świetle tego, co często tu piszesz o nietypowych platformach i
nowym/starym sprzęcie, to podchodzą jeszcze trupy.

JD

Seweryn Habdank-Wojewódzki

unread,
Feb 7, 2007, 5:02:27 PM2/7/07
to
Witam

Piotr Wyderski wrote:

> czy w boost jest jakieś gotowe rzutowanie dynamicznie
> sprawdzające zakresy przy konwersji między typami
> całkowitymi? Np.:
>
> unsigned int u = safe_cast<unsigned int>(-1);

Przez przypadek coś znalazłem:

http://www.boost.org/libs/numeric/conversion/doc/index.html

Warto zobaczyć na:

http://www.boost.org/libs/numeric/conversion/doc/converter.html#rchklogic

Seweryn Habdank-Wojewódzki

unread,
Feb 7, 2007, 5:04:40 PM2/7/07
to
0 new messages