Du bist nicht angemeldet.

Werbeanzeige

Schorsch

Supermoderator

Beiträge: 5 185

Wohnort: Wickede

Beruf: Student

  • Private Nachricht senden

21

18.06.2016, 12:33

Warum gräbst du einen 10 Jahre alten Thread aus?
Was berechnet hier nun die Funktion foo?

Keine Ahnung da du die Funktion nicht gezeigt hast und der Name nicht auf den Inhalt der Funktion schließen lässt. Mehrdimensionale Arrays sind an sich erst mal kein Problem und wie bereits gesagt kann man die auf ein eindimensionales Array übertragen. Das ist zum Beispiel für Tilemaps sinnvoll. Und das ist auch was ganz anderes als deine Structvariante. Bei deiner Variante habe ich Indizes 1-n und speichere darunter dann meine Koordinaten/Werte. Bei der Sache um die es hier geht möchte man per Koordinaten auf einen Wert zugreifen.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

22

18.06.2016, 22:52

Hab das Datum erst danach gesehen.

Dieses Beispiel soll zeigen, dass die Funktion foo einen Zeiger bekommt auf ein eindimensionales Array.
Es könnte genausogut so aussehen:

C-/C++-Quelltext

1
2
3
4
int array1[2][3];

  foo(array1, 2, 3);
  foo(array1, 3, 2);

Ausserdem kann man keine mehrdimensionalen Felder mit new anlegen (ausser mit C++11).
Und im Stack wird man wohl kaum ein größeres Feld erstellen und global erst recht nicht, da hier die Größe schon festgelegt sein muss.
Um ein dynamisches Feld mit Koordinaten kann man auch folgendes verwenden:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
int x = 300;
int y = 200;

int *array = new int[x * y];

foo(array, x, y);

delete[] array;

Hiermit kann man auch mit Tilemaps, Bitmaps und sonsiges arbeiten und die größe muss dabei nicht fix vorgegeben sein.
Der Kompiler macht auch nichts anderes als die übergebenen Werte zu Multiplizieren.
Und wenn man auf einen anderen Compiler wechselt, hat man hier am wenigsten Probleme.

In einer Struct ist das dann auch viel effizienter und hat gleich die richtigen Informationen mit dabei:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
typedef struct _S_TILEMAP
{
  unsigned m_x;
  unsigned m_y;
  int *array;

  // Constructor
  _S_TILEMAP(unsigned x, unsigned y) : m_x(x), m_y(y)  { array = new int[x*y](); }
  // Destructor
  ~_S_TILEMAP() { delete[] array; }
  // get Methode
  int get(unsigned x, unsigned y) const { return array[x*y]; }
}S_TILEMAP;

void foo(S_TILEMAP *daten)
{
  for(unsigned x = 0; x < daten->m_x; ++x)
    std::cout << daten->array[x*10];
}

void main()
{
  S_TILEMAP test2(600, 400);
  test2.array[10 * 10] = 123;
  int x = test2.get(10, 10);

  foo(&test2);
}

Hier können zusätzlich die Arraygrenzen bei get() überprüft werden, oder mit einer set() Methode die Grenzen überprüft werden, um nicht in eine ungültige Speicherstelle zu schreiben.

23

19.06.2016, 01:37

oder man gewöhnt sich einfach an, mit eindimensionalen Arrays zu arbeiten, schließlich lässt sich das Eins zu Eins aufeinander abbilden, und std::array zu verwenden...

MfG
Check
Das gibt Übersicht! Stay gold. | gnu.org | §\pi\approx\tfrac{7809723338470423412693394150101387872685594299}{2485912146995414187767820081837036927319426665}§ | Jabber: dasnacl@dasnacl.de (online?)

Schorsch

Supermoderator

Beiträge: 5 185

Wohnort: Wickede

Beruf: Student

  • Private Nachricht senden

24

19.06.2016, 12:50

Warum man in C++ jetzt mit Structs und nicht mit Klassen arbeiten soll ist mir auch neu. Ich würde std::array oder std::vector oder so etwas nehmen. Die Koordinaten eben auf ein eindimensionales Feld umrechnen und das ganze wegkapseln. Und klar kann man mit new mehrdimensionale Arrays anlegen. Ich kann per new ein Array von Arrays erstellen und dann per Schleife auf die anderen Array erstellen. Sinnvoll ist das allerdings nicht. Der Speicher kann verteilt liegen was unnötig ist "y * breite + x" kann ich auch noch grad selbst tippen.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

dot

Supermoderator

Beiträge: 9 850

Wohnort: Graz

  • Private Nachricht senden

25

19.06.2016, 13:07

Ausserdem kann man keine mehrdimensionalen Felder mit new anlegen (ausser mit C++11).

Klar kann man das und sogar auch ganz ohne C++11. Allerdings kann nur die erste Dimension dynamisch sein...

Der Kompiler macht auch nichts anderes als die übergebenen Werte zu Multiplizieren.

Was genau meinst du damit?

In einer Struct ist das dann auch viel effizienter und hat gleich die richtigen Informationen mit dabei:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct _S_TILEMAP
{
  unsigned m_x;
  unsigned m_y;
  int *array;

  // Constructor
  _S_TILEMAP(unsigned x, unsigned y) : m_x(x), m_y(y)  { array = new int[x*y](); }
  // Destructor
  ~_S_TILEMAP() { delete[] array; }
  // get Methode
  int get(unsigned x, unsigned y) const { return array[x*y]; }
}S_TILEMAP;

Inwiefern sollte das "effizienter" sein? (Insbesondere: effizienter als was?)

Ist das Absicht, dass deine Tilemap die Koordinaten (x,y), (y,x) etc. auf das selbe Tile mapped? ;)

Abgesehen davon ist dieser Stil, structs in einem typedef zu definiern ein Artfakt aus C und sollte in C++ nicht verwendet werden.

Warum man in C++ jetzt mit Structs und nicht mit Klassen arbeiten soll ist mir auch neu.

Hängt halt davon ab, was für ein Defaultverhalten man bezüglich Access-Specifier haben will. Ansonsten gibt es zwischen class und struct in C++ ja keinen Unterschied.

Ich kann per new ein Array von Arrays erstellen und dann per Schleife auf die anderen Array erstellen.

Sowas hat dann aber nichts mehr mit dem zu tun, was man in C++ normal als "mehrdimensionales Array" versteht...

26

19.06.2016, 15:50

Zitat von »Gottfried«
Der Kompiler macht auch nichts anderes als die übergebenen Werte zu Multiplizieren.


Was genau meinst du damit?

Im Assembly code sieht man dann Multiplikationen oder Shift-Operationen, damit die CPU die Speicherstelle des Elements, auf das Zugegriffen wird, errechnet wird.
Das zeigt mir der Dissasembler an bei einem int array (int = 4 Bytes)

C-/C++-Quelltext

1
2
3
4
5
6
      int val = arr[x+(breite*y)];
00AC16DF  mov         eax,dword ptr [breite] 
00AC16E5  imul        eax,dword ptr [y] 
00AC16EC  add         eax,dword ptr [x] 
00AC16F2  mov         ecx,dword ptr arr[eax*4] 
00AC16F9  mov         dword ptr [val],ecx 

Kenn mich allerdings mit den Intel Assembler nicht so aus, aber bei RISC Prozessoren sieht man die Befehle deutlicher. Bei guten Compilern wird bei Multiplikationen von 2^x hierfür die Shift-Operatoren verwendet.
Bei Mehrdimensionalen Feldern sieht es so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
      int val = arr[x][y];
009716DA  mov         eax,dword ptr [x] 
009716E0  imul        eax,eax,28h 
009716E3  lea         ecx,arr[eax] 
009716EA  mov         edx,dword ptr [y] 
009716F0  mov         eax,dword ptr [ecx+edx*4] 
009716F3  mov         dword ptr [val],eax

Hier sagt mir mein Instinkt, dass ein Eindimensionales Array schneller geht. Aber bei heutigen Prozessoren ist das im pico oder femto Bereich schneller und vernachlässigbar, bei mobilen Geräten wird das vermutlich auch keine Rolle mehr spielen.

Und sorry, anstelle von x*y muss es wie Schorsch geschrieben hat y * breite + x heissen.
Reine Daten packe ich eher in ein struct, aber hier wäre wirklich eine class besser geeignet, bin halt noch von der alten "C" Schule. Und da musste man sonst immer

Quellcode

1
struct _S_TILEMAP meinArray;
schreiben, deswegen das typedef.

BlueCobold

Community-Fossil

Beiträge: 10 888

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

27

19.06.2016, 17:37

Hier sagt mir mein Instinkt, dass ein Eindimensionales Array schneller geht.
Das is ja spannend, denn eine Multiplikation und Addition hast Du doch selbst oben erst (auch wenn's falscher Code war) für den Zugriff auf ein 1D-Array verwendet, um damit ein 2D-Array zu simulieren.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

28

19.06.2016, 23:14

Ja, aber beim 1. sind nur zwei Multiplikationen, erste mit imul und zweite mit [eax*4]
Beim 2. ist zusätzlich der lea und eine adition dazugekommen [ecx+edx*4].

1. benötigt nur 2 Register eax und ecx.
2. benötigt ein zusätzliches edx
Und bei den wenigen Registern die ein Intel hat ... Aber es gibt ja noch den 64-Bit Modus wo endlich mal 8 zusätzliche Register dazugekommen sind (R8-R15) :P

Beiträge: 1 239

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

29

19.06.2016, 23:15

Zitat

Hier sagt mir mein Instinkt, dass ein Eindimensionales Array schneller geht

Nun dein Instinkt liegt falsch. ;-)
Erstmal sind solche Kleinigkeiten wirklich echte Kleinigkeiten. Selbst wirklich performancekritischen Applikationen würde sich da nicht unterscheiden. Und zum Anderen ist das eher Zufall.

Wenn du deinem PC/Compiler was gutes tun willst, kompilier für x64. Dann gibt es mehr Register und die Werte werden nicht ständig vom Speicher gelesen. Das ist nämlich der überwiegende Teil der Dinge die in deinem Asm passieren. Für den mehrdimensionalen Fall erwarte ich prinzipiell sogar mehr Performance, weil dort die Array-Dimensionen zur Compilezeit bekannt sind.

Zum anschauen.
Was sieht man? Ein statisches 2 dimensionales Array kann (in dem Fall) ohne "teure" Multiplikation verwendet werden. Auf µOp Level sollte das effizienter sein.

BlueCobold

Community-Fossil

Beiträge: 10 888

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

30

20.06.2016, 06:35

POITROAE
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige