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?

Jsou zobrazeny jen nové odpovědi. Zobrazit všechny
Předmět Autor Datum
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á… nový
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… nový
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… nový
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… nový
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… nový
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… nový
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 (… nový
Rulda 01.06.2006 21:24
Rulda
Dynamicke pole je asi trieda ktora si to kontrolovat samozrejme moze (vsetko ide cez jej metody), ta… nový
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

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