PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : in Objekt direkt einen globalen array verwenden, ohne ihn intern zu kopieren?



HaWe
11.12.2018, 12:49
hallo,
in https://www.roboternetz.de/community/threads/72778-nochmal-Arraypointerreferenztohuwabohu?p=648608#post648608
war ja das Problem gelöst, wie man externe Listen von cstrings einlesen/übergeben kann, und diese dann intern in eine objekteigene (per new neu erzeugte) Liste kopiert und weiter verändert werden können.
Das kostet ntl doppelten Speicher, einmal für alle globalen Muster, und dann für alle einzelnen Objektinstanzen intern noch einmal.

Daher die Idee: kann man im Objekt direkt einen globalen array verwenden, ohne ihn intern zu kopieren und ohne new (per Pointer oder als Referenz, verwendbar weiterhin als public list)?


class tMenu {
public:
char ** list;

tMenu (int16_t menulen, int16_t linelen, char ** extlist, tMenu* pMenu) : // constructor
MENULEN(5), LINELEN(11), VISLNUM(5), FONTHI(13), act(0)
{
MENULEN = menulen; // number of available menu options
LINELEN = linelen; // line length of menu options
preMenu = pMenu; // predesessor menu

list = extlist; // ??????? ohne new ?????? <<<<<<<
}
}


char * mlist0[11] = {"Titel 0","Zeile1","zu menu02>","Zeile3","Zeile4","Zeile5"};
tMenu menu0(6,11, (char**)mlist0, &menu0); // numEntries, lineLength, preMenu (N/A);

char * mlist02[11] = {"Titel 02","ESC>","Zeile2","Zeile3","zu menu024"};
tMenu menu02(5,11, (char**)mlist02, &menu0); // numEntries, lineLength, preMenu=menu0;

char * mlist024[11] = {"Titel 024","ESC >","Ja","Nein","foo","bas"};
tMenu menu024(6,11, (char**)mlist024, &menu02); // numEntries, lineLength, preMenu=menu02;

Moppi
11.12.2018, 13:51
Zeiger mittels "&".

MfG

HaWe
11.12.2018, 15:05
Danke!
Habe sogar gerade festgestellt: es geht auch wie bisher schon mit dem Pointer (char**) als Aufruf-Parameter und der Zuweisung list=extlist,
allerdings muss man extrem mit der Länge der Muster-Zeilen anpassen, es geht kaum nachträglich zu manipulieren ohne Buchstabensalat zu produzieren (z.B wenn man alle Einträge mit Leerzeichen auf dieselbe Standardlänge bringen will).
Da muss ich noch ein wenig experimentieren...

- - - Aktualisiert - - -

update,
@moppi: das mit deinem "&" habe ich noch nicht hinbekommen- wie genau soll das funktionieren?

Immerhin: es funktioniert mit der direkten Pointerzuweisung, nur Einträge mit Leerzeichen auf dieselbe Standardlänge (11=10+'\0') bringen - das klappt (noch) nicht.
Der Unterschied im verwendeten RAM ist allerdings auch nicht so dramatisch....

HaWe
11.12.2018, 20:09
was ist der Grund, weshalb ich die internen list-Einträge verändern kann, wenn ich sie kopiert habe,
aber nicht, wenn ich auf die externe vorbelegte list nur per Pointer verweise?


char * mlist0[11] = {"Titel 0","Zeile1","zu menu02>","Zeile3","Zeile4","Zeile5"};
tMenu menu0(6,11, (char**)mlist0, &menu0); // numEntries, lineLength, preMenu (N/A);




protected:
void parselist(int line) {
bool issub=false;
int len=strlen(list[line]) ;

if(len<1) {
list[line][0]='#'; // min len=1
list[line][1]='\0';
len=1;
}
for(int k=len-1; k<LINELEN-1; k++) {
if(k>0 && list[line][k]=='>') {
issub=true; // styling when submenu
list[line][k]=' ';
}
if(k>0 && list[line][k]<' ') list[line][k]=' ';
}
if(issub) list[line][LINELEN-2] = '>'; // if '>' to the end
else list[line][LINELEN-2] = '.'; // default: '.' to the end
list[line][LINELEN-1] = '\0'; // cstring terminator
}

HaWe
16.12.2018, 10:02
hat sich geklärt, beim Initialisieren werden die einzelnen array-cstrings komprimiert gespeichert, als wären sie Konstanten, ohne freie Restlänge.
Außerdem bezeichnet bei
char * liste[n]
das n sowieso nicht die Einzel-Länge der cstrings wie ich fälschlich dachte, sondern die Anzahl der cstrings insgesamt.

Moppi
26.12.2018, 12:43
Hallo HaWe,

entschuldige bitte, dass ich nicht mehr nachgesehen hatte und also nicht geantwortet, aber ich hatte sowieso kein Patentrezept.


das mit deinem "&" habe ich noch nicht hinbekommen- wie genau soll das funktionieren?

Du suchtest - verkürzt ausgedrückt - nach einem Weg, auf Speicherinhalt zuzugreifen, ohne ihn zu kopieren.
Ein Weg wäre mit dem "&", Beispiel:


pWert = &Wert; // Adressoperator '&' liefert die Adresse einer Variable

Quelle hier. (https://de.wikibooks.org/wiki/C%2B%2B-Programmierung/_Weitere_Grundelemente/_Zeiger)

Damit solltest Du über den Adresszeiger auf die Variable zugreifen können (oder Array etc., hat ja alles seine Speicheradresse).
Das war mein Gedanke dabei.
Du müsstest eben nur Deiner Funktion oder Methode die Adresse der Variablen übergeben.


MfG

HaWe
28.12.2018, 10:23
Theoretisch ist das schon klar, aber wie sieht der Code für die Initialisierung und die Referenzierung der 2-dim cstring arrays dann exakt praktisch als lauffähiger C/++ Code aus?
Als Beispiel s. mein Example für die Menu Class Lib, die ich hier schon gepostet habe
https://www.roboternetz.de/community/threads/72806-Vorstellung-Arduino-C-Menu-Lib-%28ARM-oder-ESP-ggf-auch-AVR%29

Moppi
28.12.2018, 11:43
Theoretisch ist das schon klar..

Super, dachte ich auch so! :)

Praktisch fällt mir dazu noch ein, dass es u.U. nicht möglich ist einfach so von überall auf Variablen per Speicheradresszeiger zuzugreifen. In objektorientierter Programmierung könnte in den dortigen Methoden ein Strich durch die Rechnung gemacht werden, weil man theoretisch nicht einfach irgendwo im Speicher hingreifen kann (Schutzmechanismen). Ob das in C/C++ einfach so geht, weiß ich auch nicht, weil ich mich mit C so weit noch nicht beschäftigt habe. Wenn die Zeiger aber ordentlich übergeben werden, viele mir aber kein Grund ein, warum das nicht funktionieren sollte, solang der Compiler weiß, was gemeint und in Maschinencode zu tun ist.

MfG

HaWe
28.12.2018, 18:07
Hallo,
Nein, du hast von einer Referenz gesprochen (&) , ich habe aber einen Pointer verwendet, nur per Pointer habe ich es geschafft, nicht aber mit deinem &

Moppi
28.12.2018, 20:56
Na ja, von Zeiger hatte ich schon gesprochen. Die Beispielseite hatte ich auch verlinkt, dort steht auszugsweise:


int *pWert; // eine Zeigervariable, zeigt auf einen int
pWert = &Wert; // Adressoperator '&' liefert die Adresse einer Variable

Das ist die richtige Vorgehensweise, wie man auch hier sieht: https://www.arduino.cc/reference/en/language/structure/pointer-access-operators/reference/


int *p; // declare a pointer to an int data typeint i = 5, result = 0;
p = &i; // now 'p' contains the address of 'i'
result = *p; // 'result' gets the value at the address pointed by 'p'

// i.e., it gets the value of 'i' which is 5

Man muss ja eine Variable als Zeiger nehmen, wo man die Adresse mittels "&" reinlädt. Das ist nun mal so. Muss man dann dazu eben eine Variable als Zeiger/Pointer definieren, wenn es nicht anders geht.

MfG

HaWe
29.12.2018, 09:47
Du verstehst nicht den Punkt:
Man kann Varaiblen per * als Pointer übergeben, wie ich es getan habe, oder per & als Referenz (Adresse ), wie du es oben geschrieben hast.
Zu deinem Vorschlag fehlt aber noch der tatsächlich funktionierende Code zu dem beschriebenen 2-dim array Problem. Hier ist mir noch schleierhaft, wie du einen
char*mlist[n ] = {"a", "foo", "dfghj",.... }

referenziert per & an die Objektinstanz übergeben willst, so dass man dort darauf als array
char list [m ][n ]
Oder als
char** list
zugreifen kann.

Schreib doch mal bitte diesen genauen, getesteten Code hier rein, wie du das meinst.

Moppi
29.12.2018, 10:32
HaWe, das mag sein.

Es ist eigentlich ganz einfach. ab 386er/486er aufwärts:

mov edx, offset meineVariable
mov bp, SegmentVonVariable

verschiedene Varianten für den Zugriff:

mov ax,bp:[edx]
mov ax,bp:[edx+1]
mov ax,bp:[edx+bx]

Entscheidend ist, ob ein Zugriff aus dem aktuellen Segment auf ein anderes überhaupt möglich ist. Das wird im Protected Mode via Descriptoren definiert und der CPU beim Erstellen eines neuen Segments (Programm oder Daten oder Stack) mitgegeben. Stimmen die Privilegien von Aufrufer und Ziel nicht überein, führt das zu einer Ausnahme.

//-----------------------------------------------------------

Wie das jetzt hier bei den Kontrollern so ist, weiß ich nicht, so weit habe ich mich dafür noch nicht interessiert. Wie oben in dem Beispiel zu sehen ist, benötigt man die Adresse der Variablen, über indirekte Adressierung kann man dann darauf zugreifen. So kenne ich das. Wenn man in C/C++ eine indirekte Adressierung nur über Pointer-Variablen hinbekommt (bspw: *p), dann ist das so. Wenn Du den Offset der externen Variablen anders dort rein bekommst, auch gut. Aber: die entscheidenden Hinweise sind: "Zeiger" und "&". Ob das ein oder andere für die Lösung des Problems relevant ist, musst Du dann schauen.

MfG

HaWe
03.01.2019, 14:51
Also asm hilft hier nun wirklich nicht weiter... ;)
Mich interessiert nur, wie man es ganz praktisch in C alternativ die Variablenübergabe (in diesem Falle einen 2-dim char array) an eine Funktion per Referenz codiert, so wie du es vorgeschlagen hast, sodass es ebenfalls so wie mit der Übergabe mit Hilfe von Pointern funktioniert.

global im Hauptprogramm:

char mlist0[6][11] = {"Titel 0","Zeile1","zu menu02>","Zeile3","Zeile4","Zeile5"};

Und wie muss hier die lokale list innerhalb der Objekt-Funktion defiiniert werden? Die Funktion "weiß" ja zunächst noch gar nicht, wie groß die Dimensionen des Arrays sind, die "6" und die "11" werden der Objekt-Instanz ja erst gesondert bei der Instantiierung mitgeteileilt - daher verwende ich bisher den "Doppel-Pointer" als Platzhalter

class tMenu {
public:
char ** list;
//
}



(editiert)

Moppi
03.01.2019, 15:13
Was immer Du meinst, habe ich mich damit nicht weiter beschäftigt. Gut ist, dass Du es hinbekommen hast!


Und wie muss hier die lokale list innerhalb der Objekt-Funktion defiiniert werden? Die Funktion "weiß" ja zunächst noch gar nicht, wie groß die Dimensionen des Arrays sind, die "6" und die "11" werden der Objekt-Instanz ja erst gesondert bei der Instantiierung mitgeteileilt.
(editiert)

Vielleicht kann das jemand anders sagen, der da tiefer in C++ drin steckt als ich.
Aber eines kann ich sagen: Funktionen in OOP, in einem Objekt / einer Instanz davon heißen Methoden.
Wenn man mit Objekten arbeitet, ist es normal, dass die Speicher fressen, jede Instanz ist eine Kopie - hast Du inzwischen ja auch schon bemerkt. Deshalb muss man sich überlegen, ob das Sinn macht oder ob man auf Objekte verzichtet und ohne OOP mit Funktionen arbeitet. Normalerweise sollte man doch per Bibliothek auch nur Funktionen einbinden können, ohne dass man gleich mit OOP zuschlägt (?).

MfG

HaWe
03.01.2019, 15:33
Vielleicht kann das jemand anders sagen, der da tiefer in C++ drin steckt als ich.
Aber eines kann ich sagen: Funktionen in OOP, in einem Objekt / einer Instanz davon heißen Methoden.

MfG
ja, danke, das hoffe ich auch!
Immerhin ist die Übergabe-Syntax aber ja grundsätzlich überall gleich, an alle möglichen Funktionen (oder Methoden), und dieser Teil ist plain C Code, nicht C++ spezifisch.