Autor Wątek: Zagadki językoznawcze  (Przeczytany 56465 razy)

Offline Shelim

  • Użytkownik
    • Homepage

# Kwiecień 05, 2009, 16:40:21
Wychodzę z ideą zorganizowania małego konkursu na językoznawstwo (mam na myśli tutaj głównie C++, ale jak ktoś zaproponuje inny popularny język - czemu nie?). Zasady:
 + W temacie pada zagadka, kto na nią odpowie, może zadawać jako następny ew. zrzec się prawa; wtedy obowiązuje zasada: kto pierwszy, ten lepszy.
 + Jako zagadkę podajemy krótki (powiedzmy do 50 linii) kod źródłowy z pytaniem: "jaki będzie rezultat?"
 + Nie stosujemy kompilatorów do odpowiedzi (!) Odpowiadajmy na podstawie wiedzy a nie, "wklepałem do IDE i zadziałało tak, więc musi być tak". Zawsze trzeba uargumentować odpowiedź: dlaczego dzieje się tak, a nie inaczej.
 + Pytania powinny dotyczyć bardziej języka niż konkretnych bibliotek. Zadasz podchytliwkę z OpenGla, a ktoś od 15 lat programuje w DirectX i co wtedy?
 + W sytuacjach spornych decydujący głos ma standard języka. Nawet jeżeli jakiś kompilator go nie przestrzega. Period.

Zagadka numer 1 (z podziękowaniami dla DrG, który zainspirował mnie do stworzenia konkursu):
int a(short i)
{
  return i;
}

int a(int i)
{
  return -i;
}

int main(int argv, char** argc)
{
  short b = 666;
  if ( ( a(b)-a(b-1) ) == 1 )
  {
    cout << "Odpowiedz 1" << endl;
  } else
  {
    cout << "Odpowiedz 2" << endl;
  }
}
Co zostanie wypisane?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Charibo

  • Redaktor

# Kwiecień 05, 2009, 16:54:41
Na moje, wypisana zostanie odpowiedź 2, bo dla a(b-1) wywoła się overload dla inta. :)

Teraz zagadka ode mnie:
Kod: (cpp) [Zaznacz]
int zonk(int a, int b)
{
return a + b;
}

int main()
{
int i = 5;
std::cout << zonk(++(++i), (++i)++);
return 0;
}
:P ;D
« Ostatnia zmiana: Kwiecień 05, 2009, 16:59:08 wysłana przez Charibo »

Offline Kos

  • Użytkownik
    • kos.gd

# Kwiecień 05, 2009, 16:57:08
UB :)

therealremi

  • Gość
# Kwiecień 05, 2009, 17:09:21
Na moje, wypisana zostanie odpowiedź 2, bo dla a(b-1) wywoła się overload dla inta. :)

Super, ale dlaczego wywoła się overload dla inta? Jaka reguła języka o tym mówi? Korialtrash wyraźnie napisał, że nie będziemy się bawić w "na moje", "wydaje mi się", "bo sprawdziłem w Visualu" itp.

Offline Aithne

  • Użytkownik

# Kwiecień 05, 2009, 17:17:58
Bo 1 jest typu int?

Offline Kos

  • Użytkownik
    • kos.gd

# Kwiecień 05, 2009, 17:25:09
Mamy odejmowanie short-int, więc mniej dokładny typ awansuje do bardziej dokładnego przed operacją. Ot :)

therealremi

  • Gość
# Kwiecień 05, 2009, 17:47:34
Bo 1 jest typu int?

A dlaczego 1 jest typu int ?  :) Dlaczego nie short int? Albo char?

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Kwiecień 05, 2009, 17:55:50
Cytuj
Na moje, wypisana zostanie odpowiedź 2, bo dla a(b-1) wywoła się overload dla inta. :)
Wypisze się odpowiedź 2., bo tak wychodzi z zasad matematyki (-666 - (-665) = -666 + 665 = -1). Żadne tajemnicze castowania tutaj nie zmieniają zupełnie niczego, bo wszystkie liczby i wyniki pośrednie są bez problemów reprezentowalne jako shorty.

Cytuj
Mamy odejmowanie short-int, więc mniej dokładny typ awansuje do bardziej dokładnego przed operacją.
Wątpliwe. Takie coś produkowało by niezliczoną ilość warnów przy po każdej operacji na shortach/charach (potencjalnie groźne castowanie z inta na typ o niższej precyzji), a tak przecież nie ma. Jestem na 99% pewien, że przy operacji short-1 nie ma żadnych tajemniczych upcastów.

Cytuj
Teraz zagadka ode mnie:
Proponuję, żeby chociaż autor kompilował zadawane zadania, w razie niepewności. ;) Nie dość, że podany kod jest niedeterministyczny (standard nie precyzuje, w jakiej kolejności wykonują się operacje pre/post-inkrementacji/dekrementacji w przypadku wielu parametrów funkcji), to jeszcze się w ogóle nie skompiluje. Operacje pre/post-inkrementacji/dekrementacji zwracają wartość zmiennej, a nie referencje do niej, więc na czymś takim już nie da się wykonywać dalszych takich operacji. ;)


A żeby nie było nudno, to zagadka nr 3 ode mnie:
int  main()
{
    int a = 65536;
    int b = 10000;

    while(a&&b)
    {
        if(a>b) a-=b;
        else    b-=a;
    }

    printf("%d\n",a|b);

    return 0;
}

Offline Charibo

  • Redaktor

# Kwiecień 05, 2009, 18:05:39
Cytuj
Teraz zagadka ode mnie:
Proponuję, żeby chociaż autor kompilował zadawane zadania, w razie niepewności. ;) Nie dość, że podany kod jest niedeterministyczny (standard nie precyzuje, w jakiej kolejności wykonują się operacje pre/post-inkrementacji/dekrementacji w przypadku wielu parametrów funkcji), to jeszcze się w ogóle nie skompiluje. Operacje pre/post-inkrementacji/dekrementacji zwracają wartość zmiennej, a nie referencje do niej, więc na czymś takim już nie da się wykonywać dalszych takich operacji. ;)
Ja zaś proponuję, żeby ktoś, kto twierdzi, że się nie kompiluje faktycznie sprawdzić czy się nie kompiluje. :P MSVC9 nie ma żadnych obiekcji co do tego kodu. :) W temacie zaś nie było mowy o tym, że trzeba zadawać takie-a-nie-inne pytanie, toteż, IMO, zagadka której celem było pokazanie UB jest na miejscu. ;)


therealremi

  • Gość
# Kwiecień 05, 2009, 18:12:44

Krzysiek K., krótko mówiąc napisałeś dużo NIEPRAWDY.

Po pierwsze:
Standard języka C
Rozdział 6.4.4.1
Cytuj
An integer constant begins with a digit, but has no period or exponent part. It may have a
prefix that specifies its base and a suffix that specifies its type.
...
The type of an integer constant is the first of the corresponding list in which its value can
be represented.
I poniżej jest fajna tabelka, w której dla stałych dziesiętnych bez przyrostka jest kolejno:
int, long int, long long int
Jak widać nie ma char ani short int mimo iż 1 zmieściłoby się w tych typach.

To jest odpowiedź na "Żadne tajemnicze castowania tutaj nie zmieniają zupełnie niczego, bo wszystkie liczby i wyniki pośrednie są bez problemów reprezentowalne jako shorty."

A co do "Jestem na 99% pewien, że przy operacji short-1 nie ma żadnych tajemniczych upcastów."
to zapoznaj się z Rozdziałem 6.3.1.8 -"Usual arithmetic conversions" bo nie ma sensu wklejać tyle tekstu.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Kwiecień 05, 2009, 19:40:29
Cytuj
MSVC9 nie ma żadnych obiekcji co do tego kodu. :)
Hmm, dziwne - najwidoczniej zależy to od kompilatora, bo sam parę lat temu bawiłem się w tego typu udziwnienia kodu i podwójne inkrementacje nie chciały przejść (kompilator: GCC). Przed chwilą sprawdziłem w VC++ - dla preinkrementacji jednak działa (więc Twój kod jest OK), ale dla postinkrementacji już nie.

Cytuj
A co do "Jestem na 99% pewien, że przy operacji short-1 nie ma żadnych tajemniczych upcastów."
to zapoznaj się z Rozdziałem 6.3.1.8 -"Usual arithmetic conversions" bo nie ma sensu wklejać tyle tekstu.
OK, sprawdziłem i rzeczywiście cała pośrednia matma dzieje się na intach. Dlatego napisałem na 99%, a nie na 100%, więc zawsze ten 1% akurat mógł się sprawdzić. :)

Offline Kos

  • Użytkownik
    • kos.gd

# Kwiecień 05, 2009, 20:36:33
int  main()
{
    int a = 65536;
    int b = 10000;

    while(a&&b)
    {
        if(a>b) a-=b;
        else    b-=a;
    }

    printf("%d\n",a|b);

    return 0;
}

Myślę, że Twój program zwróci 0. :)

A jeśli przypadkiem chodzi o stdout... hmm, 16? :D

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Kwiecień 05, 2009, 22:02:17
Cytuj
Myślę, że Twój program zwróci 0. :)
Nie zwróci. :)


Fakt, że może zadanie bardziej algorytmiczne niż językoznawcze, ale dla ułatwienia dodam, że jest to znany algorytm od dość dawna (gdzieś IV wiek p.n.e.) :)

Offline Aithne

  • Użytkownik

# Kwiecień 05, 2009, 23:08:25
Nie zwróci.
To co zwróci? Na końcu maina jest return 0, a wszelkie _mainCRTStartupy (nazwa oczywiście zależna od kompilatora) zwracają to, co zwrócił main. A jeśli chodzi o to, co program WYPISZE, to pewnie będzie to 16 (jeżeli a && b da false to któraś zmienna musi być 0, a X | 0 da X), jak już Kos napisał.

Offline raver

  • Użytkownik
    • Moja strona domowa.

# Kwiecień 05, 2009, 23:52:05
IMO kod Krzyśka K to algorytm na największy wspólny dzielnik. W pamięci wyszedł mi dzielnik 16. (65536 to 2 do którejśtam, a dzieląc 10000 przez 2 wychodzi po kolei: 5000, 2500, 1025).