Modyfikacja adresu wskaźnika

0
RS := TResourceStream.Create(HInstance,'data', RT_RCDATA);
RS.Read(RS_przes^,rs.Size);

Ten kawałek ładuje dane bezposrednio do zarezerowanej wczesniej pamięci. Jak wczytac te same dane z przesunięciem np o 100 bajtów do tej samej pamięci

0
RS.Read(Pointer(RS_przes + 100)^, RS.Size);

lub inaczej:

Inc(RS_przes, 100);
RS.Read(RS_przes^, RS.Size);

O to chodzi? Jeśli nie to wytłumacz dokładniej.

0
var   Identyfikator1 :THandle;
      AdresE1 :pointer;

Function EdytorActivPointer:Pointer;
Begin
   EdytorActivPointer:=adresE1;
End;

Procedure x;
Var
    RS : TResourceStream;
Begin



  Identyfikator1:=GlobalAlloc(gmem_Fixed+gmem_ZeroInit,$02000000);
  AdresE1:=GlobalLock(Identyfikator1);

  RS := TResourceStream.Create(HInstance,'PLIK', RT_RCDATA);

  //Chodzi mi o to żeby do zarezerwowanej pamięci z pod wskażnika AdresE1 wgrać dane z plik do pamięci z przesunieciem 100 bajtów

  RS.Read(EdytorActivPointer^,rs.Size);

End;
0

Byle jak opisujesz problem, to i trudno zrozumieć co masz na myśli.

Jak dobrze rozumiem, masz wskaźnik AdresE1 i do niego chcesz wczytać porcję danych. Dane te mają zostać wczytane ze strumienia RS. I teraz Ty potrzebujesz wczytać dane z tego strumienia, ale nie od jego początku, a najpierw przesunąć kursor o 100 i dopiero wtedy wczytać. Racja?

Jeśli tak to skorzystaj z właściwości RS.Position i wpisz do niej wartość 100 - kursor (inaczej mówiąc wskaźnik) w strumieniu zostanie przesunięty na bajt o indeksie 100 (licząc od 0), dzięki czemu metoda RS.Read rozpocznie odczytywanie porcji danych właśnie od tego bajtu. Skoro dane nie będą czytane od początku strumienia to w drugim parametrze trzeba to uwzględnić i odjąć liczbę pomijanych bajtów.

const
  STREAM_OFFSET = 100;

{..}
  
RS := TResourceStream.Create(hInstance, 'PLIK', RT_RCDATA);

RS.Position := STREAM_OFFSET;
RS.Read(EdytorActivPointer()^, RS.Size - STREAM_OFFSET);

Przy okazji - nazwij te zmienne sensownie. RS to zły identyfikator, a EdytorActivPointer ma błąd, bo słówko Active pisze się z e na końcu.

0

Mi chodzi nie o przesunięcie strumienia a gdzie dane będą już zapisane czyli w pamięci nie od pierwszego bajtu tylko z przesunięciem.

0

Podałem to w pierwszym swoim poście.

0

Nie działa tak podczas komilaci mam błedy.

tak na początku miałem i chodziło ale bufor był ładowany od pierwszego bajtu

RS.Read(RS_przes^, RS.Size);

i chodziło dobrze, ale ładuje plik od początku pamięci

Po zamianie na :

Inc(RS_przes, 100);   // błąd: ordinal type required
RS.Read(RS_przes, RS.Size);  // bład operand not applicable to this operand type
0
Inc(RS_przes, 100);   // błąd: ordinal type required

Jakiego typu jest to RS_przes?

RS.Read(RS_przes, RS.Size);  // bład operand not applicable to this operand type

Brakuje operatora ^.

0
  RS_przes:Pointer;  


 Inc(RS_przes^, 100);  jak do tego dorzuce ^ to mam błąd //incompatybile types
 RS.Read(RS_przes^, RS.Size); bo tu jest dobrze
0
Inc(RS_przes^, 100);  // jak do tego dorzuce ^ to mam błąd incompatybile types

Dziwisz się? Nie wstawiaj na pałę operatorów - myśl co robisz. W pierwszym parametrze Inc masz podać wskaźnik, a nie zawartość na którą wskazuje (której i tak w tym przypadku typ nie jest znany).


No dobra, mały przykład, co prawda testowany w Lazarusie, ale także z dyrektywą {$mode delphi}:

const
  SOME_STRING = 'furious'#0'programming'#0;
var
  L1stWord: Pointer;
  L2ndWord: Pointer;
begin
  L1stWord := @SOME_STRING[1];
  L2ndWord := @SOME_STRING[9];

  WriteLn('"', PChar(L1stWord), '"');
  WriteLn('"', PChar(L2ndWord), '"');

  WriteLn('"', PChar(L1stWord + 8), '"');  // z przesunięciem dodatnim o 8 bajtów
  WriteLn('"', PChar(L2ndWord - 8), '"');  // z przesunięciem ujemnym o 8 bajtów
end.

Zadanie programu jest proste - wyświetlić to na co wskazują dwa wskaźniki:

  • L1stWord - wskazuje na słówko furious,
  • L2ndWord - wskazuje na słówko programming.

Na ekranie konsoli zobaczymy to:

"furious"
"programming"
"programming"
"furious"

I teraz najważniejsze - co się dzieje w wywołaniach Writeln, są cztery:

  1. wyświetlenie zawartości wskazywanej przez L1stWord - wskaźnik zawiera adres pierwszego znaku pierwszego słowa, więc wyświetlane jest pierwsze słowo (słowo, bo do wystąpienia znaku NULL),
  2. wyświetlenie zawartości wskazywanej przez L2ndWord - wskaźnik zawiera adres pierwszego znaku drugiego słowa, więc wyświetlane jest drugie słówki,
  3. wyświetlenie ciągu na podstawie wskaźnika L1stWord i dodaniego przesunięcia o 8 bajtów - osiem bajtów dalej leży pierwszy znak drugiego słowa, więc ono zostaje wyświetlone,
  4. wyświetlenie ciągu na podstawie wskaźnika L2ndWord i ujemnego przesunięcia o 8 bajtów - osiem bajtów wcześniej leży pierwszy znak pierwszego słowa, więc ono zostaje wyświetlone.

Jak widzisz, w dwóch ostatnich wywołaniach obsługiwane są przesunięcia. Użyłem tutaj zwykłej arytmetyki, aby adresy zawarte w obu wskaźnikowych zmiennych nie uległy zmianie. Jeżeli zależy Ci na tym, aby zwiększyć adres w zmiennej to skorzystaj z Inc, która już od bardzo dawna wspiera wskaźniki.

0

no tak ale jak zrobie

Inc(RS_przes, 100);   // błąd: ordinal type required

to też mam bład

0

Jakiego używasz kompilatora? Wszystkie podane w tym wątku kody sprawdziłem w Lazarusie, z dyrektywą {$mode objfpc} i {$mode delphi}, kompilują się i działają bez problemu. Nawet z {$mode tp}.

0

Dalej nie wiem jak to zrobić technicznie rozumiem ze jak rs_przes to mam adres gdzie jest to w pamięci a jak mam rs_przes^ to jest wskaznik gdzie jest zapisany adres.
Komilator delphi2009.

1

Dalej nie wiem jak to zrobić technicznie rozumiem ze jak rs_przes to mam adres gdzie jest to w pamięci a jak mam rs_przes^ to jest wskaznik gdzie jest zapisany adres.

No nie bardzo rozumiesz. Samo rs_przes to zawartość wskaźnika, czyli adres na który wskazuje. rs_przes^ (z operatorem ^) to dane, na które wskazuje ten wskaźnik. Dwa różne zapisy, więc i dwa różne rezultaty - adres danych lub wartość danych.

Co do samego problemu - nie mam Delphi 2009 (ani żadnego innego) aby to sprawdzić, jednak podane konstrukcje są prawidłowe. Nie wiem dlaczego taki zapis akurat w tym środowisku nie jest prawidłowy. Zawsze można użyć pomocniczej zmiennej do przechowania adresu z offsetem - spróbuj skompilować poniższy kod, jako prostą konsolówkę:

var
  LData, LDataOffset: Pointer;
begin
  LData := nil;
  LDataOffset := LData + 100;
end.

Jeśli się skompiluje to tymczasowo użyć pomocniczej zmiennej, a jeśli nie to trzeba szukać dalej.

1

Taki trochę "łopaciany" sposób, ale może zadziała (u mnie jest OK):

program Test;

type
  //wskaźnik musi być rzutowany na odpowiedni typ
  //zależnie od architektury
  {$Ifdef  CPU64}
  MyInt = QWord;
  {$Else}
  MyInt = LongWord;
  {$endIf}

var
  P: Pointer;
  L : QWord;
  Offset : byte;
begin
  P := @L; //przypisujemy zmienną do wskaźnika
  readln(L); //wczytujemy wartość do zmiennej (tu 8 bajtów)
  readln(Offset); //wczytujemy przesunięcie dla bajtu, który chcemy zobaczyć
  OffSet := OffSet and 7; // to tylko dla bezpieczeństwa w tym przykładzie (OffSet mod 8)
  Writeln(Byte(Pointer(MyInt(P)+Offset)^)); //wyświetlamy zmienną typu Byte,
     //z adresu wskaźnika P przesuniętym o Offset
  readln; //by nie zamknęło od razu
end.    

Ogólnie to polega na:

  1. Rzutowaniu wskaźnika na zmienną liczbową
  2. Dodaniu przesunięcia
  3. Ponownemu rzutowaniu na wskaźnik
  4. Tu w celu wyświetlenia jest rzutowanie wartości wskaźnika na Byte
0

Przykład pawel24pl działa. I teraz pytanko. Czy jeśli nie wstawię

 {$Ifdef  CPU64}
  MyInt = QWord;
  {$Else}
  MyInt = LongWord;
  {$endIf}

To program nie będzie działał na procesorach 64 bitowych czy tylko to jest potrzebne do kompilacji?

Dziekuje

1

Macie tam chyba takie typy danych jak PtrUInt czy PtrInt? Jak macie to nie bawcie się we własne definicje.

To program nie będzie działał na procesorach 64 bitowych czy tylko to jest potrzebne do kompilacji?

Program będzie działał na obu typach procesorów. Te dyrektywy są porzebne jedynie do kompilacji (kompilator na podstawie istniejących definicji pomija ten niepasujący kod), tak jak zresztą każde inne ifdefy.


Edit: Moment, bo skomentowałem fragment cytatu, bez początku... Jeśli nie wstawisz tego kodu, do nie będziesz mógł używać typu MyInt - to logiczne.

Jeśli wstawisz ten kod i skompilujesz go kompilatorem 32-bitowym dla 32-bitowej platformy, to program będzie działał zarówno na Windows 32-bit, jak i 64-bit. Jeżeli skompilujesz go dla 64-bitowej platformy to program da się uruchomić jedynie na Windows 64-bit.

No, teraz wszystko powinno być jasne.

0

Dziękuje temat uważam za zakończony. Podziękowania dla furious programming i pawel24pl.

1 użytkowników online, w tym zalogowanych: 0, gości: 1