Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailem Smerniky - pravda alebo nepravda?

V jednej nemenovanej literature som sa pri citani smernikovej aritmetiky docital nasledovne: "smerniky nemozeme scitavat, mozeme ich len odcitat a odcitanim dvoch smernikov dostaneme vzdialenost dvoch objektov v jednotkach ich dlzky". Tak som to teda v Delphi urobil, ale nejak sa kod nechcel prelozit. V com je problem? Je vobec takato veta pravdiva?

Předmět Autor Datum
Pravda to asi je, jen me nejak nenapada k cemu by to bylo dobry.
Wikan 30.05.2006 09:15
Wikan
To by som aj ja rad vedel, len nechapem, preco to potom nefunguje. Ked som chcel odcitat sva smernik…
Intex 30.05.2006 09:17
Intex
Co a kedy ti to hlasi? Jak to "nefunguje"? Ono aj odcitavanie smernikov je problematicke (ak by sa m…
MM.. 30.05.2006 13:46
MM..
Ako priklad som urobil taketo nieco, neviem, ci to je spravne: ... var p1, p2: ^integer; pole: arra…
Intex 30.05.2006 16:23
Intex
Hm, tu http://info.borland.com/techpubs/delphi/delphi5/opl g/syntlmnt.html v sekcii pointers operato…
MM.. 30.05.2006 16:58
MM..
Prerobil som to na smerniky, ktore ukazuju na typ char, lenze ani tak to nefunguje: "Operator not ap…
Intex 30.05.2006 18:59
Intex
Tak to neviem. Je mozne ze to robi preto ze mas v nastaveniach projektu nastavene ze char ma byt 2by…
MM.. 30.05.2006 19:16
MM..
S tym integerom to tiez nefunguje... Odcitavat smerniky si chcem len odskusat, nepotrebujem to na ni…
Intex 30.05.2006 19:22
Intex
No ak by to fungovalo tak by to vypisalo cislo 1. Kedze to v delphi nefunguje tak to nepouzivaj :-)
MM.. 30.05.2006 19:35
MM..
Ak by to fungovalo... lenze preco to nefunguje, ked aj v jazykovej referencii Object Pascal sa pise,…
Intex 30.05.2006 19:46
Intex
Ak je tam chyba tak IMHO len v nastaveni projektu. Schvalne skus si vypisat alebo si pozri debuggero…
MM.. 30.05.2006 21:27
MM..
Skusim to...
Intex 31.05.2006 08:55
Intex
V Turbo Pascale boli pre kompilátor direktívy: - Typed @ operator - Open parameters Alternatívy v D…
msx. 30.05.2006 23:47
msx.
Myslim, ze som to uz skusal aj s tym, ale tiez nic... ale skusal som iba jeden parameter... skusim v…
Intex 31.05.2006 08:52
Intex
Odcitani ukazatelu dava v C pocet prvku.
kubik 30.05.2006 17:58
kubik
Podla toho v akom jazyku. Ja robim vacsinou v Jave a tam ziadne smerniky nie su. Smernik je len bin…
x22 30.05.2006 15:24
x22
Podle me jsou smerniky i Javě.;-)
MaSo 30.05.2006 15:28
MaSo
Smernik je sice len cislo, ale vo vyssom jazyku ako assembler treba vidiet aj suvislost s tym ako je…
MM.. 30.05.2006 15:38
MM..
Všetko sa točí okolo smerníkov. Je len otázkou jazyka, ako ich pekne zabalí, aby to používateľ čo na…
msx. 30.05.2006 15:39
msx.
Jestli tě dobře chápu, tak hledáš v nápovědě tohle: You can use the + and - operators to increment…
Rulda 31.05.2006 16:44
Rulda
Ano myslel som na to... skusal som aj PChar, ale ani s nim to nejde...
Intex 31.05.2006 21:12
Intex
To snad ani není možné ... ukaž kód (s PChar), který nefunguje.
Rulda 31.05.2006 21:28
Rulda
Smerniky na staticke premenne: var p1, p2: pchar; s1, s2: ^pchar; begin p1:= pchar('a'); p2:= pchar…
Intex 01.06.2006 15:03
Intex
Ano, teď je již problém jasný. Typ PChar je totiž již ukazatel sám o sobě (proto to P na začátku) T…
Rulda 01.06.2006 15:55
Rulda
Noooooooooooo... ano funguje to... ale preco to nefunguje na typy ako napr.: integer, byte a pod...
Intex 01.06.2006 16:10
Intex
Tak to mohu jen hádat, ale s pravděpodobností hraničící s jistotou bych tvrdil že proto, že to nemá…
Rulda 01.06.2006 16:31
Rulda
V C to funguje tak, ze by sa to posunulo o 4 integery, t.j. ak integer ma 4byty tak by i2 ukazoval o…
MM.. 01.06.2006 16:50
MM..
Pokud by to Delphi umělo, asi by to taky posunulo o 16 Byte. Alespoň u PWideChar posun o jeden znak…
Rulda 01.06.2006 19:29
Rulda
samozrejme ze v C by po int *i1, *i2; i2 = i1 + 4; by bolo i2 o 16 vacsie ako i1 (ak je int 32bito…
MM.. 01.06.2006 19:43
MM..
Ne ne ne, nebylo. Stále mě nechápeš. Já nemám na mysli adresu, kam bude ukazovat i2. Já se ptám na o…
Rulda 01.06.2006 20:25
Rulda
Tak snad nie je programator dement a ked napise i2 = i1 + 4 tak asi na tej adrese ma ulozeny nejaky…
MM.. 01.06.2006 20:55
MM..
jj, s tím D máš pravdu. :-[ Před I zrovna žádnou proměnnou nemám. V Delphi se pro přístup do pole (…
Rulda 01.06.2006 21:24
Rulda
Dynamicke pole je asi trieda ktora si to kontrolovat samozrejme moze (vsetko ide cez jej metody), ta…
MM.. 01.06.2006 21:37
MM..
Ale i Delphi si mohu prvek pole uložit do další proměnné, nebo třeba jen adresu na něj. Nikdo neřekl… poslední
Rulda 01.06.2006 21:52
Rulda

To by som aj ja rad vedel, len nechapem, preco to potom nefunguje. Ked som chcel odcitat sva smerniky v Delphi, nespustil som to... proste sa to neda... preto ma zaujima, ci to je vobec mozne... Viem, ze take zistenie je k nicomu, ale ako to potom urobit, ked v tejto literature sa to uvadza (nie je tam vsak priklad a tiez tam nie je ani, v ktorom jazyku to bolo myslene)...

Co a kedy ti to hlasi? Jak to "nefunguje"?
Ono aj odcitavanie smernikov je problematicke (ak by sa mixovali smerniky na napr. lokalnu a globalnu premennu ale to by bol principialne nezmysel).

P.S. v C to myslim mozne je (smernik je len adresa), ale treba davat pozor na to co bude vysledok, ci len rozdiel tych adries alebo pocet prvkov (t.j. ci aj deleno dlzka typu smernika) to ani zhlavy neviem ako to prekladac robi, snazil by som sa takym veciam vyhnut...
v delphi neviem, napis co to hlasi.

Ako priklad som urobil taketo nieco, neviem, ci to je spravne:

...
var p1, p2: ^integer;
    pole: array[1..10] of integer;
begin
  ListBox1.Items.Clear; // prebehne vypocet
  for i:= 1 to 10 do
    pole[i]:= i;
  p1:= @pole[1];
  p2:= @pole[10];
  for i:= 1 to 5 do
    begin
      p1^:= p1^ + p2^;
      p2^:= p1^ - p2^;
      p1^:= p1^ - p2^;
      inc(p1);
      dec(p2);
    end;
  for i:= 1 to 10 do
    ListBox1.Items.Add(IntToStr(pole[i]));
  ShowMessage(IntToStr(p1 - p2)); // tu vznikne problem
...
end;
 

Pri kompilacii sa program ani neprelozi, hned vyhlasi chybu, uz presne neviem aka, ale je to: operand nie je akceptovatelny... nemam teraz spustene Delphi... proste, ze tento operand tam nema co hladat...

edit: p1 a p2 su smerniky na staticke lokalne pole...

Prerobil som to na smerniky, ktore ukazuju na typ char, lenze ani tak to nefunguje: "Operator not applicable to this operand type"... teraz uz fakt neviem. Podla tej prirucky, co si sem dal, by to malo fungovat. Naopak to fungovat nemoze, o tom viem. Ale odcitat by ist malo... Prirucka je to popisom jazyka Object Pascal v Delphi 5. Nemoze to byt tym, ze ja to robim v Delphi 6?

Tak to neviem. Je mozne ze to robi preto ze mas v nastaveniach projektu nastavene ze char ma byt 2bytovy (WideChar), a on to vie len pre jednobytove, ale to len hadam, moze tam byt iny problem netusim az tak delphi nepoznam.
Este by som skusil dat to extra do riadku akoze nejaky integer = p1-p2, ale to imho nepomoze. Char je aj tak len -127 az 128 alebo 0 az 255, neviem ci ti to staci, urob to radsej inac aby si nemusel odcitavat smerniky a mas pokoj. Nepamatam sa ze by som niekedy potreboval odcitavat smerniky.

Ak by to fungovalo... lenze preco to nefunguje, ked aj v jazykovej referencii Object Pascal sa pise, ze sa to da urobit... ja viem, je mi to nanic, aj tak to nevyuzijem... hladam po googli, nachadzam vsetko mozne ale skoro vsetko v C. Musi to predsa fungovat aj v Delphi... je tam niekde malicka chybicka. Ale neviem kde...

Smernik je sice len cislo, ale vo vyssom jazyku ako assembler treba vidiet aj suvislost s tym ako je definovana operacia scitania, ak mam napr. v C smernik na long int, tak smernik+1 bude v skutocnosti (na 32bit platforme) znamenat adresu smernik+4 (lebo dlzka long int je 4byty), o to sa stara prekladac otazne je ci je vobec zadefinovane scitanie typov smernik+smernik, a ako je zadefinovane odcitanie typov smernik - smernik, ci sa to aj deli velkostou typu (v tom pripade by slo odcitavat len smerniky na rovnaky typ premennej) apod.
Delphi take veci zvykne kontrolovat viac ako C takze verim ze tam bude viac obmedzeni. Otazka je ake presne smerniky dotazovatel odcitava, a co mu to hlasi.

Jestli tě dobře chápu, tak hledáš v nápovědě tohle:

You can use the + and - operators to increment and decrement the offset of a character pointer. You can also use - to calculate the difference between the offsets of two character pointers. The following rules apply.

If I is an integer and P is a character pointer, then P + I adds I to the address given by P; that is, it returns a pointer to the address I characters after P. (The expression I + P is equivalent to P + I.) P - I subtracts I from the address given by P; that is, it returns a pointer to the address I characters before P. This is true for PChar pointers; for PWideChar pointers P + I adds SizeOf(WideChar) to P.

If P and Q are both character pointers, then P - Q computes the difference between the address given by P (the higher address) and the address given by Q (the lower address); that is, it returns an integer denoting the number of characters between P and Q. P + Q is not defined.

Pozn. character pointer = PChar

Smerniky na staticke premenne:

var p1, p2: pchar;
    s1, s2: ^pchar;
begin
  p1:= pchar('a');
  p2:= pchar('A');
  s1:= @p1;
  s2:= @p2;
  showmessage(inttostr(s2 - s1)); // tu vznikne chyba...
end;

Novo vytvorene dynamicke premenne:

var s1, s2: ^pchar;
begin
  new(s1);
  new(s2);
  s1^:= pchar('a');
  s2^:= pchar('A');
  showmessage(inttostr(s2 - s1)); // tu vznikne chyba...
  dispose(s1);
  dispose(s2);
end;

Chyba: "Operator not applicable to this operand type". Jedna sa o Delphi 6. Je v tom nieco zle?

Ano, teď je již problém jasný. Typ PChar je totiž již ukazatel sám o sobě (proto to P na začátku)

The generic PChar represents a pointer to a Char

takže s1 a s2 jsou něco jako ukazatel na ukazatel ;-)

Tvůj kód by měl vypadat takto:

var p1, p2: pchar;
    s1, s2: ^pchar;
begin
  p1:= pchar('a');
  p2:= pchar('A');
  s1:= @p1;
  s2:= @p2;
  showmessage(inttostr(p2 - p1));
end;

Tak to mohu jen hádat, ale s pravděpodobností hraničící s jistotou bych tvrdil že proto, že to nemá valného smyslu. U PChar má smysl posouvat se v řetězci, ale co dostaneš, pokud posuneš ukazatel na integer o 1 výš?

Příklad s PChar:

var p1, p2: pchar;
begin
  p1 := 'Hello world';
  showmessage(p1);  //zobrazi text 'Hello world'
  p2 := p1 + 6;
  showmessage(p2);  //ukazatel posunu o 6 znaku, zustane 'world'
  p2 := p2 + 2;  
  showmessage(p2); //ukazatel posunu o dalsi 2 znaky, zustane jen 'rld'
  showmessage(IntToStr(p2 - p1));  //pocet znaku mezi p1 a p2 (6+2=8)
end;

Ale co by jsi dostal, pokud by se ti podařilo přeložit následující kód (jakože nepodaří) ;-)

var i1, i2: Pinteger;
begin
  i1^ := 123456;
  i2 := i1 + 4;  //co by bylo obsahem i2^ ?
end;

Myslím, že na tuto otázku by nedokázal odpovědět ani sám velký Jan Fiala, pokud by nesměl použít vulgarismy :-)

Pokud by to Delphi umělo, asi by to taky posunulo o 16 Byte. Alespoň u PWideChar posun o jeden znak (+1) znamená posun o 2 byte.
Stále to ale neodpovídá na mou (řečnickou) otázku. Pokud by jsi výše uvedený kód přepsal do C, jaký by byl obsah i2^ po provedení

i2 := i1 + 4;

?
Rozlišujme použití v řetězcích (resp. polích), kde známe "souseda", a použití na samostatných proměnných, které mohou sousedit s čímkoliv.

Pozn. Já netvrdím, že tato konstrukce (přičítání/odečítání hodnoty k adrese) nemá opodstatnění. Pro kompilátor je ale v mnoha případech obtížné (ne-li nemožné) určit datový typ, na jaký bude adresa po této operaci ukazovat, což je pro Pascal, jakožto jazyk s přísnou typovou kontrolou, nepřijatelné.

Pozn2. Konstrukci přičítání/odečítání k/od adresy lze i v Delphi implementovat pomocí přetypování, ale v Pascalu se na to hledí jako na "nečisté" programování.

var p: pointer;
begin
p := Pointer(Integer(p) + 16);
end;

samozrejme ze v C by po

int *i1, *i2;
i2 = i1 + 4;

by bolo i2 o 16 vacsie ako i1 (ak je int 32bitovy), ved som to pisal, je to aj povolene, C nikdy nekontroluje ci smernik neukazuje za koniec pola ani nic podobne, to je vec programatora.

Je mozne ze pascal to robi kvoli kontrole, ale potom nechapem preco pripusta aritmeticke operacie (aj pripocitanie cisla) s PChar, a nepripusta s PInteger, ved to je to iste akurat ze u PInteger by bolo este nasobenie offsetu velkostou integeru.

Ne ne ne, nebylo.
Stále mě nechápeš. Já nemám na mysli adresu, kam bude ukazovat i2. Já se ptám na obsah proměnná integer na paměťovám místě, kam ukazuje i2. Pascalská konstrukce

i2^

dereferencuje ukazatel, takže to už není adresa, ale číslo velikosti integer na místě, kam adresa ukazuje.
Mě je přece jasné, KAM by ukazatel ukazoval. Chci říct, že to nemá smysl, protože programátor předem neví, co se na té adrese nachází . (no dobře, v mnoha případech zkušenější programátor ví, že tam bude určitá proměnná, která byla deklarována hned vedle, ale je určitě lepší použít přímo tu proměnnou). Proto jsem tvrdil, že obvykle nemá smysl takto posouvat adresu z jedné proměnné.
Něco jiného je to v řetězcích. Pokud PChar ukazuje na znak, lze předpokládat, že na adrese P1+1 (kde p1 je PChar) bude taky znak. Proto je tato konstrukce povolena. Pokud ale mám násl. kód:

var I: Integer;
D: Double;
L: Longint;
S: String;
P: Pointer;
PI: PInteger;
begin
  I := 12345;
  PI := @I;
  PI := PI + 1; //toto neni v Pascalu povoleno; predpokladejme ze se ukazatel posune o integer, tedy 4B
end;

tak já sice vím, že po jeho provedení bude PI ukazovat na D, ale to už není integer, takže hodnota v PI^ bude (alespoň zdánlivě) nesmyslná.

Tak snad nie je programator dement a ked napise
i2 = i1 + 4
tak asi na tej adrese ma ulozeny nejaky integer ;-)

Ak robis serioznejsi/zlozitejsi program tak sa uz nehras s nejakymi statickymi poliami ale napr. si alokujem pamat pre xy integerov

i1 = malloc(xy*sizeof(int))

a potom si nastavim i2 na 5-ty integer v tom

i2 = i1 + 4;

Taketo veci prekladac nema sancu kontrolovat ptz. nevie pri preklade kolko bude xy, a ani to od prekladaca nechcem aby sa mi do takychto veci montoval, to je moj problem co na tej adrese bude :-)

P.S. inac ten PI v tvojom programe by na koci IMHO neukazoval na D, ptz. lokalne premenne v zasobniku sa alokuju postupne (teda myslim ze v C to je tak), t.j. od vyssich adries k nizim (lebo zasobnik).
Inac ked ti ide o to co by precital v tvojom priklade, no precital by 4byty z toho miesta na ktore ukazuje ten pointer (ak by to bolo mimo segmentu programu tak "program proved neplatnou operaci a bude ukoncen". Prekladac nema co zaujimat co znamena to cislo ktore je ulozene na tej adrese, on ho prsote precita a tym to hasne, vyznam zaujima len programatora. Ak by ukazoval na nejake Double tak by precital prve 4 byty z Double ako integer (aj to sa moze niekedy hodit :-))

jj, s tím D máš pravdu. :-[ Před I zrovna žádnou proměnnou nemám.

V Delphi se pro přístup do pole (i dynamického) používají indexy, takže takovéto konstrukce jsou zbytečné. A možná to bude důvod, proč to nejde (zamezení zbytečným chybám).
Mimochodem, Delphi je schopné kontrolovat správný rozsah indexu při přístupu do pole dokonce i na dynamických polích, za předpokladu že programátor zapne kontrolu rozsahu.

Pascal velmi zajímají datové typy. (nezmiňoval jsem se o tom už?) Proto i typový ukazatel jako PInteger by měl ukazovat opravdu na integer. Samozřejmě i jen trochu zkušenější programátor to umí obejít (např. zmiňovaným přetypováním), ale tyto prostředky jsou určeny jsou určeny právě zkušenějším programátorům kteří vědí, co dělají.
Takže to shrnu: V řetězcích (a v céčku v polích) může být přičítání adres užitečné. V ostatních případech stěží.
Pokud někdo zná další použití, pro které nemá Delphi rovnocennou náhradu, tak sem s tím.

Dynamicke pole je asi trieda ktora si to kontrolovat samozrejme moze (vsetko ide cez jej metody), taku triedu si samozrejme mozem urobit (a aj to v C++ knizniciach urobene je) aj v C++
Inac ide trochu aj o efektovnost pri casovo kritickych veciach, preco mam pouzit index a pri kazdom pristupe to musi CPU preratavat/indexovat, ak mozem pracovat rovno s adresou. Samozrejme rozdiel nie je velky (indexovat bezne typy sa daju tiez v jednej asm instrukcii), ale ja som programator tak si chcem zvolit sposob taky aky ja chcem, nie prekladac je programator :-)

Trochu sme odbocili od povodnej temy - odcitanie smernikov, naco to je - no prave na to ako tu zadal program dotazovatel, mal dva smerniky ukazujuce na rovnake pole integerov, rozne s obomi hybal, a chcel na konci zistit odcitanim smernikov, ze kolko prvkov je "medzi nimi", co mu Delphi nedovolil. Netvrdim ze je to nutne, pisal som na zaciatku ze som odcitavat smerniky nepotreboval ani nepamatam, ale zrovna zakazovat/neimplementovat to podla mna nie je to co by som od prekladaca cakal...

Ale i Delphi si mohu prvek pole uložit do další proměnné, nebo třeba jen adresu na něj. Nikdo neřekl, že to nejde. Jen k té adrese nemohu jednoduše přičíst číslo.
Pokud chci zjistit vzdálenost prvků pole od sebe, prostě odečtu jejich indexy. Stejně tak s indexy lze provádět jakékoliv matematické operace včetně sčítání a odčítání; jsou to prosté integery. Takže posun o 2 prvky dál je jen I+2.
Dynamická pole nejsou třídy, ale pouze alokovaná oblast paměti, kterou kompilátor zprostředkovává jako pole záznamů. To že si to vyloží jako pole (a zná počet prvků) je díky tomu, že se velikost pole nastavuje speciální procedurou SetLength (není to metoda). Ta alokuje potřebnou paměť podle typu, který bude v poli uložen.
Ale souhlasím, že kontrola rozsahu má jistou režii. Proto je implicitně vypnutá.

Zpět do poradny Odpovědět na původní otázku Nahoru