Še ena C uganka

Vse o programiranju na in za PC

Moderatorji: Kroko, tilz0R

Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 17:57

Koda: Izberi vse
int a=0;
int b=0;
test1((a++, b+=a, b++));

Kakšni parametri se pošljejo v funkcijo test1?

Koda: Izberi vse
test2(a++, b+=a, b++);

Kaj pa v test2?
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a gumby » 28 Sep 2016, 18:24

Kroko je napisal/-a:test1((a++, b+=a, b++));

Ta klic je sploh veljaven?
my brain hurts
Uporabniški avatar
gumby
 
Prispevkov: 2573
Pridružen: 14 Jan 2015, 19:49
Kraj: Lendava
Zahvalil se je: 108 krat
Prejel zahvalo: 604 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 63

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 18:41

Ja, ta klic je veljaven.

Meni so take uganke všeč. Na ekstremnih primerih piliš svoje znaje in se naučiš kaj novega. Nikakor pa to ni za začetnike.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a peterp » 28 Sep 2016, 18:48

Takšni primeri so za moje pojme popolnoma neuporabni. Res je, da se lahko marsikaj naučiš (in ponavadi se res :) ) ampak če bi take zadeve videl v resni kodi bi si tudi mislil svoje.
peterp
 
Prispevkov: 657
Pridružen: 23 Feb 2015, 14:52
Kraj: Maribor
Zahvalil se je: 164 krat
Prejel zahvalo: 112 krat
Uporabnika povabil: gumby
Število neizkoriščenih povabil: 114

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 19:17

Seveda to ni primerno za resno kodo. Je pa zanimivo, da ni še nihče poskusil tele uganke razložiti, saj izgleda nadvse preprosto :twisted:
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a igo » 28 Sep 2016, 19:18

Test1(1,1,1);
Test2(1,1,1); // saj bi napisal (2,3,4), a se mi zdi, da razni a++, ne povečajo originalnega a, kadar so uporabljeni kot argumenti za klicanje funkcije. Sicer bi funkcijo parkrat zapored poklical in bi moral vsakič prednastaviti pravkar podrte vrednosti spremenljivk.

Pišem na slepo, moral bi napisati funkciji, ki izpišeta a, b in c ter preveriti.

Navajanje takih ++ += akrobacij znotraj argumentov za klic funkcije je povsem veljavno.
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1492
Pridružen: 11 Apr 2015, 13:38
Kraj: Krško
Zahvalil se je: 174 krat
Prejel zahvalo: 364 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 35

Re: Še ena C uganka

OdgovorNapisal/-a igo » 28 Sep 2016, 19:22

Aaaaahhh. Dva oklepaja. Tega sploh nisem opazil. :_banghead :oops:

Sem mislil, da je bistvo uganke ravno v tem, da se najprej pokliče test1, takoj zatem pa še test2 .
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1492
Pridružen: 11 Apr 2015, 13:38
Kraj: Krško
Zahvalil se je: 174 krat
Prejel zahvalo: 364 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 35

Re: Še ena C uganka

OdgovorNapisal/-a tilz0R » 28 Sep 2016, 19:23

Visual studio ne prevede prvega, drugi pa pravi tako:

prvi = 0;
drugi = 1;
tretji = 0;

Razlaga za moje pojme je sledeča: najprej se izvedejo ukazi branja a++ in b++ (prvi in tretji parameter), kasneje se povečata oba na 1. Drugi aprameter se kasneje izvede, ampak se spet najprej prebere (b = 1), kasneje se poveča za 1 na b = 2 ampak to več ni zontraj funkcije.

Disasembly visual studia:
Koda: Izberi vse
0138180C  mov         eax,dword ptr [b] 
0138180F  mov         dword ptr [ebp-0DCh],eax 
01381815  mov         ecx,dword ptr [b] 
01381818  add         ecx,1 
0138181B  mov         dword ptr [b],ecx 
0138181E  mov         edx,dword ptr [b] 
01381821  add         edx,dword ptr [a] 
01381824  mov         dword ptr [b],edx 
01381827  mov         eax,dword ptr [a] 
0138182A  mov         dword ptr [ebp-0E0h],eax 
01381830  mov         ecx,dword ptr [a] 
01381833  add         ecx,1 
01381836  mov         dword ptr [a],ecx 
01381839  mov         edx,dword ptr [ebp-0DCh] 
0138183F  push        edx 
01381840  mov         eax,dword ptr [b] 
01381843  push        eax 
01381844  mov         ecx,dword ptr [ebp-0E0h] 
0138184A  push        ecx 
0138184B  call        test1 (0138135Ch) 
01381850  add         esp,0Ch 
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1815
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 229 krat
Prejel zahvalo: 509 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 19:43

Hm,

Koda: Izberi vse
void test1(int a, int b, int c) {}
test1((a++, b+=a, b++));

main.c:15:5: error: too few arguments to function 'test1'                                                                                                                           
     test1((a++, b+=a, b++));
     ^


Očitno se konstrukt (a++, b+=a, b++) prenese kot en sam parameter, saj napaka izgine, če test1 definiram kot funkcijo enega parametra,

Koda: Izberi vse
void test1(int a) {
    printf("%d\n", a);
}


Izgleda, da se od celega oklepaja prenese le zadnji parameter.

Koda: Izberi vse
    int c;
    printf("c=%d\n", (c=0,++c,++c));


izpiše c=2, torej se izvedejo tudi stavki prej v oklepaju, vrne pa le rezultat zadnjega?
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 20:01

Aja, še odgovor. Glede na do sedaj videno, bi rekel, da se v test1 pošlje parameter 1, v test2 pa (če je bil prej pognan test1), se prenesejo 1,4,4, čeprav koda pa pravi 1,4,2.

Aha, jasno, pri parametrih ni zaporedne evalvacije, oba b-ja imata isto začetno vrednost (na poziciji 2 in 3). Torej res 1,4,2.
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 20:07

Ja, dvojni oklepaj se z lahkoto spregleda. Drug "trik" je pa vejica
https://en.wikipedia.org/wiki/Comma_operator

Upam, da je test1 sedaj vsem jasen.

Kaj pa test2? Tu vejica samo loči parametre. Lahko kdo poskusi z različnimi prevajalniki?

Aja, test2 je povsem samostojen, se zaganja brez testa1. Takole:
Koda: Izberi vse
int a=0;
int b=0;
test2(a++, b+=a, b++);
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a tilz0R » 28 Sep 2016, 20:14

Kroko, poglej mojo razlago.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1815
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 229 krat
Prejel zahvalo: 509 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 20:24

Z razlago nisem zadovoljen. Nisi razložil zakaj je tako naredil.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a tilz0R » 28 Sep 2016, 20:28

Ker imajo ++ in - - ujazi prednost pred ostalim.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1815
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 229 krat
Prejel zahvalo: 509 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 20:33

Če vklopim vsa opozorila (-Wall) pri gcc, kompajler javi mutna posla :).

Koda: Izberi vse
main.c: In function 'main':                                                                                                                                                         
main.c:19:23: warning: operation on 'b' may be undefined [-Wsequence-point]                                                                                                         
     test2(a++, b+=a, b++);                                                                                                                                                         
                       ^                                                                                                                                                           
main.c:19:12: warning: operation on 'a' may be undefined [-Wsequence-point]                                                                                                         
     test2(a++, b+=a, b++);                                                                                                                                                         
            ^                                         
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 20:35

@tilz0R

Potem bi dobil
Koda: Izberi vse
prvi = 1;
drugi = 1;
tretji = 1;

in ne
prvi = 0;
drugi = 1;
tretji = 0;


@booxco
Tako je. Tak primer ni definiran. Rezultati so nepredvidljivi. Dober prevajalnik mora vrniti opozorilo.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a tilz0R » 28 Sep 2016, 20:37

Ni res Kroko. Potem bi dobil 0,1,0 ker najprej beres, potem povecas. Ne vidim undefined behaviourja tukaj.
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1815
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 229 krat
Prejel zahvalo: 509 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 20:43

C specifikacija ne definira, da najprej bereš in nato povečaš. Vsak prevajalnik to naredi po svoje. Dober na to opozori.
https://en.wikipedia.org/wiki/Sequence_point
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a tilz0R » 28 Sep 2016, 20:46

I++ ali ++I je jasna stvar kako je sekvenca. Lahko bi bilo tudi tukaj :)
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1815
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 229 krat
Prejel zahvalo: 509 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 21:03

Še en zanimiv primer:

Koda: Izberi vse
   
    c=0;
    printf("1: c=%d, %d, %d, %d, %d\n", c++,c++,c++,c++,c++);
    c=0;
    printf("2: c=%d, %d, %d, %d, %d\n", c++,c++,c,c++,c++);


Dobim
1: c=4, 3, 2, 1, 0
2: c=3, 2, 4, 1, 0

torej vrstni red od desne proti levi v prvem primeru, v drugem podobno le kot da bi ++ res imeli prednost, kot pravi tilz0r. (gcc version 5.3.1 20151207 (Red Hat 5.3.1-2)). Seveda ob kupu opozoril, da je koda nepredvidljiva.
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a radix » 28 Sep 2016, 21:09

booxco je napisal/-a:...torej vrstni red od desne proti levi v prvem primeru, v drugem podobno le kot da bi ++ res imeli prednost, kot pravi tilz0r. (gcc version 5.3.1 20151207 (Red Hat 5.3.1-2)). Seveda ob kupu opozoril, da je koda nepredvidljiva.
Kateri nivo optimizacije (-O ali O1, -O2, -O3, -Os ...) je vključen?
radix
 
Prispevkov: 1468
Pridružen: 04 Feb 2015, 20:19
Kraj: Ljubljana
Zahvalil se je: 226 krat
Prejel zahvalo: 349 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 24

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 21:11

radix je napisal/-a:
booxco je napisal/-a:...torej vrstni red od desne proti levi v prvem primeru, v drugem podobno le kot da bi ++ res imeli prednost, kot pravi tilz0r. (gcc version 5.3.1 20151207 (Red Hat 5.3.1-2)). Seveda ob kupu opozoril, da je koda nepredvidljiva.
Kateri nivo optimizacije (-O ali O1, -O2, -O3, -Os ...) je vključen?



Nič,

gcc -Wall -o main *.c
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a radix » 28 Sep 2016, 21:52

Šele zdaj vidim, da je v drugi vrstici programa en c brez incrementa. Potem so operacije čisto razumljive. Najprej opravi vse operacije s post incrementom po vrsti od desne proti levi in na koncu prebere še vrednost c.
Ta program:
Koda: Izberi vse
   int c = 0;
   printf("1: %d, %d, %d, %d, %d\n", c++, c++, c++, c++, c++);
   c = 0;
   printf("2: %d, %d, %d, %d, %d\n", c++, c++, c++, c++, c++);
pa da ven tak rezultat (jasno, pri vseh nivojih optimizacije enak):
Koda: Izberi vse
1: 4, 3, 2, 1, 0
2: 4, 3, 2, 1, 0
Pri tem so warningi enaki kot v prejšnjem primeru.
radix
 
Prispevkov: 1468
Pridružen: 04 Feb 2015, 20:19
Kraj: Ljubljana
Zahvalil se je: 226 krat
Prejel zahvalo: 349 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 24

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 22:09

Zna kdo tole razložit?

Koda: Izberi vse
#include <stdio.h>

int main(void) {
    int c = 0;
   printf("1: %d, %d, %d, %d, %d\n", ++c, ++c, ++c, ++c, ++c);
   c = 0;
   printf("2: %d, %d, %d, %d, %d\n", ++c, ++c, c++, ++c, ++c);
   return 0;
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 22:13

Kot sem napisal - obnašanje v takih primerih ni definirano. Nima smisla več razpravljati.

Še ena zanimiva:

Koda: Izberi vse
int a = -2147483648;
int b = -1;
int c = a / b;

Koliko je c in zakaj?
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a tilz0R » 28 Sep 2016, 22:16

Pomoje je še kr -2147483648 :D
Knowledge sharing is people' caring., T. MAJERLE
Uporabniški avatar
tilz0R
 
Prispevkov: 1815
Pridružen: 18 Jan 2015, 00:12
Kraj: Črnomelj
Zahvalil se je: 229 krat
Prejel zahvalo: 509 krat
Uporabnika povabil: s56rga
Število neizkoriščenih povabil: 255

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 22:59

Jasno je fail, saj pride -2147483648/-1=-2147483648, sicer uganke ne bi bilo.

Zgleda smo nekje na robu, ker če eno odštejemo, skočimo v +:

Koda: Izberi vse
int a = -2147483648;
printf("a=%d, a-1=%d\n", a, a-1);

a=-2147483648, a-1=2147483647


Tule se signed int lomi. Verjetno je krivo nekaj s tem robom in pa Cjevskem zaokroževanjem pri deljenju integerjev. Ker če računamo v float aritmetiki, je rezultat ok. (torej float c = a * 1.0/ b; pride v redu 2147483648.000000)
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a booxco » 28 Sep 2016, 23:05

Saj sem si sam odgovoril. 2147483648 (pravilni rezultat) je v bistvu gornji (a-1)+1, kar je pa enako a oziroma -2147483648.
booxco
 
Prispevkov: 113
Pridružen: 25 Sep 2016, 22:17
Zahvalil se je: 18 krat
Prejel zahvalo: 47 krat
Uporabnika povabil: radix
Število neizkoriščenih povabil: 9

Re: Še ena C uganka

OdgovorNapisal/-a Kroko » 28 Sep 2016, 23:58

Največji možni integer je 2147483647.
http://www.planet-cnc.com poskakuješ na eni nogi in žvižgaš alpske podoknice Kroko was here!
Uporabniški avatar
Kroko
 
Prispevkov: 4773
Pridružen: 14 Jan 2015, 12:12
Kraj: Ljubljana
Zahvalil se je: 680 krat
Prejel zahvalo: 1652 krat
Uporabnika povabil: Vrtni palček
Število neizkoriščenih povabil: 255


Vrni se na Programski jeziki

Kdo je na strani

Po forumu brska: 0 registriranih uporabnikov in 1 gost