C ist "freier" als Pascal

Für sonstige Unterhaltungen, welche nicht direkt mit Lazarus zu tun haben
Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: C ist "freier" als Pascal

Beitrag von Warf »

Mathias hat geschrieben:
Warum kann man Prozeduren keine statischen Arrays übergeben?

Bei mir geht dies

Code: Alles auswählen

procedure WriteArray(a: array of byte);
var
  i: integer;
begin
  for i := 0 to Length(a) - 1 do begin
    Write(a[i], ' ');
  end;
  WriteLn();
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  sa: array[50..100] of byte;
  i: integer;
begin
  WriteArray(sa);
  for i := Low(sa) to High(sa) do begin
    sa[i] := i;
  end;
  WriteArray(sa);
end;   

Dabei habe ich einen Nebeneffekt entdeckt, das die Werte der Arrray am Anfang undefiniert sind.


Hier hast du einen kleinen Fehler gemacht:deine Funktion WriteArray bekommt ein Argument eines Offenen Arrays. Dein array[50..100] of byte; ist ein Statischer Array. Beim Aufruf wird der statische Array dann umgewandelt in einen Offenen Array.

Wenn du wirklich einen Statisches Array übergeben willst, musst du dir dies erst als eigenen Typen definieren:

Code: Alles auswählen

type
  TByteArr50To100 = array[50..100] of Byte;


Dann kannst du es auch in Parametern verwenden, musst aber dann natürlich von Low nach High iterieren

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: C ist "freier" als Pascal

Beitrag von Mathias »

Wenn du wirklich einen Statisches Array übergeben willst, musst du dir dies erst als eigenen Typen definieren:

Klar, wen die Array immer gleich gross ist, dann muss man natürlich einen Typ deklarieren, so wie es bei ein Record auch der Fall ist.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: C ist "freier" als Pascal

Beitrag von Timm Thaler »

Warf hat geschrieben:Wenn du wirklich einen Statisches Array übergeben willst, musst du dir dies erst als eigenen Typen definieren:


Ja, das hat mich auch schon gewundert:

Code: Alles auswählen

type
  dbuf = record
    ttim : TDateTime;
    vval : array[1 .. chnmax] of real;
  end;       
var
  datbuf : array[0 .. cdatmax - 1] of dbuf;
 


datbuf muss bei 0 beginnen, wenn ich es in einer Prozedur übergeben will. Aber vval arf bei 1 beginnen. ;-)

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: C ist "freier" als Pascal

Beitrag von Timm Thaler »

Wie ist das eigentlich bei dynamischen Arrays: Wenn ich in einer Prozedur ein statisches Array datenbuffer : array[0..max] of real habe und das per LoadData(datenbuffer); an eine Prozedur übergebe, die mit procedure LoadData(var daten : array of real); deklariert ist, ist ja daten ein dynamisches Array von datenbuffer. Daten, die ich da reinschreibe, stehen nach Ende der Prozedur auch in datenbuffer.

Wird dabei ein neues Array daten angelegt und die Daten aus datenbuffer da rein und am Ende der Prozedur wieder zurückkopiert? Oder wird nur ein Zeiger auf datenbuffer übergeben? Was nebenbei eine vernünftige Erklärung wäre, warum die dynamischen Arrays immer bei Null anfangen.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: C ist "freier" als Pascal

Beitrag von Warf »

Timm Thaler hat geschrieben:Wie ist das eigentlich bei dynamischen Arrays: Wenn ich in einer Prozedur ein statisches Array datenbuffer : array[0..max] of real habe und das per LoadData(datenbuffer); an eine Prozedur übergebe, die mit procedure LoadData(var daten : array of real); deklariert ist, ist ja daten ein dynamisches Array von datenbuffer. Daten, die ich da reinschreibe, stehen nach Ende der Prozedur auch in datenbuffer.

Wird dabei ein neues Array daten angelegt und die Daten aus datenbuffer da rein und am Ende der Prozedur wieder zurückkopiert? Oder wird nur ein Zeiger auf datenbuffer übergeben? Was nebenbei eine vernünftige Erklärung wäre, warum die dynamischen Arrays immer bei Null anfangen.


Der Parameter ist immer noch ein Offenes Array und kein Dynamisches, Technisch wird es realisiert wie ein Statisches Array (also der Speicherblock der übergeben wird hat eine feste unveränderbare Länge, welche beim Aufruf feststehen muss), darum lassen sich Statische Arrays sehr leicht (implizit) in Offene Überführen, Dynamische Arrays allerdings nicht (grad gesehen: nur in Delphi, fpc konvertiert dir auch einen Dynamisches Array implizit). Wenn du nun das ganze als Referenz (var keyword) übergibst, so wird intern nur ein Zeiger auf das erste Element deines Statischen Arrays übergeben. (entspricht damit also der value übergabe eines Dynamischen arrays).

Es ist allerdings nicht so ganz wie ein Dynamisches Array, da ein Dynamisches Array sich da durch auszeichnet dass man SetLength aufrufen kann, was ja (logischerweise) nicht funktioniert

Wenn du einen Statischen Array einem Offenen Array per Value übergibst, so wird der gesamte Array bei der Übergabe kopiert, und ist dann im parameter als offenes Array 0 basiert, unabhängig von den ursprünglichen Arraygrenzen.

Außerdem kann man auch Teilarrays übergeben:

Code: Alles auswählen

procedure foo(arr: array of Byte);
...
 
var arr: Array[0..10] of Byte;
...
  foo(arr[1..5]); // übergibt einen array der Größe 5 mit den Elementen 1-5 des arrays arr


Dynamische Arrays fangen bei 0 an, damit sie mit der Zeigerarithmetik übereinstimmen, damit funktioniert dieser tolle Code:

Code: Alles auswählen

var p: PInteger;
  i: Integer;
begin
  p:=GetMem(5*SizeOf(integer));
  for i:=0 to 4 do
    p[i] := i;
  FreeMem(p);
end.


Da Dynamische Arrays somit Äquivalent zu Zeigern auf ein Array sind

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: C ist "freier" als Pascal

Beitrag von Timm Thaler »

Warf hat geschrieben:Wenn du nun das ganze als Referenz (var keyword) übergibst, so wird intern nur ein Zeiger auf das erste Element deines Statischen Arrays übergeben... Wenn du einen Statischen Array einem Offenen Array per Value übergibst, so wird der gesamte Array bei der Übergabe kopiert, und ist dann im parameter als offenes Array 0 basiert, unabhängig von den ursprünglichen Arraygrenzen.


Das heisst, wenn ich nicht möchte, dass mein Array bei der Übergabe kopiert wird, sollte ich das immer mit var übergeben, auch wenn die Prozedur im Array nichts ändert. Klingt eigentlich logisch.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: C ist "freier" als Pascal

Beitrag von Warf »

Timm Thaler hat geschrieben:Das heisst, wenn ich nicht möchte, dass mein Array bei der Übergabe kopiert wird, sollte ich das immer mit var übergeben, auch wenn die Prozedur im Array nichts ändert. Klingt eigentlich logisch.


Nein, dafür gibt es das const Schlüsselwort. Damit wird ein Zeiger of das Objekt übergeben, allerdings jedwede Veränderung ausgeschlossen. Somit wird nur der Zeiger Kopiert (was die performance erhöht), aber gleichzeitig der Nebeneffekt das sich die Werte ändern können unterbunden.

Ohne keyword wiederum wird der Wert immer kopiert, dafür ist das Argument in der Funktion selbst dann als normale veränderbare Variable zur Verfügung. Wenn man die Werte nur lesen möchte, und die Daten größer als ein Pointer(64 Bit) sind, und die Performance relevant ist, sollte man immer const verwenden

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: C ist "freier" als Pascal

Beitrag von Mathias »

Code: Alles auswählen

var
  p: ^Integer;
  i: integer;
begin
  p := GetMem(5 * SizeOf(integer));
  for i := 0 to 4 do begin
    p[i] := i;
  end;
 
  FreeMem(p);
end

Interessant, wie man den Integer-Pointer, als Array ansprechen kann. Sowas habe ich bis jetzt nie probiert, ausser bei Byte und Char.
Im Grunde, ist der PChar auch nichts anderes.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: C ist "freier" als Pascal

Beitrag von Warf »

Mathias hat geschrieben:

Code: Alles auswählen

var
  p: ^Integer;
  i: integer;
begin
  p := GetMem(5 * SizeOf(integer));
  for i := 0 to 4 do begin
    p[i] := i;
  end;
 
  FreeMem(p);
end

Interessant, wie man den Integer-Pointer, als Array ansprechen kann. Sowas habe ich bis jetzt nie probiert, ausser bei Byte und Char.
Im Grunde, ist der PChar auch nichts anderes.


Um ehrlich zu sein braucht man es auch nicht, arrays sind dank ihrer referenzzählung und dem der length Funktion eh viel angenehmer. So muss man nur arbeiten wenn man das letzte Bit optimieren möchte

Antworten