Forum: Mikrocontroller und Digitale Elektronik Arduino: Größe eines Pointers


von Roth (Gast)


Lesenswert?

Kurze Frage: Wie lang ist in Arduino-C ein Pointer, 16 oder 32 Bit?

Tippe sehr auf 16 Bit, aber tippen ist nicht wissen. danke.

von avr (Gast)


Lesenswert?

Kommt auf den Arduino an. Arduino-C gibt es übrigens nicht (und auch 
kein Arduino-C++). Mit sizeof findest du die Größe heraus.

von Klaus (Gast)


Lesenswert?

avr schrieb:
> Mit sizeof findest du die Größe heraus.

Was hilft es einem, wenn man das weiß?

MfG Klaus

von Roth (Gast)


Lesenswert?

avr schrieb:
> Arduino-C gibt es übrigens nicht

'tschuldigung. C für Arduino meine ich.

avr schrieb:
> Mit sizeof findest du die Größe heraus.

Könntest du dir vorstellen, dass ich die Variable erst anlegen will?

von Einer K. (Gast)


Lesenswert?

Roth schrieb:
> Könntest du dir vorstellen, dass ich die Variable erst anlegen will?

Was hält dich ab?

von Roth (Gast)


Lesenswert?

Roth schrieb:
> Könntest du dir vorstellen, dass ich die Variable erst anlegen will?

ähm es kann sich keiner vorstellen ... :(

Ich erkläre dann mal. Also ich will Pointer in Variablen speichern. 
Genau genommen Funktionspointer, also Pointer auf Funktionen.

Zu Arduino-C: Könntze mir vorstellen, dass die Größe von Variablen mit 
der (max)Größe des Speichers/EEPROMS korreliert. Daher müsste es keinen 
Sinn machen, Pointern in einer relativ kleinen Welt 32 Bit zu 
spendieren.

Aber meine Frage signalisiert mein Unwissen. Ich weiß nicht, wie groß 
der C-Compiler Pointer für die Arduino-Plattform macht. Daher die Frage.

von Roth (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Roth schrieb:
>> Könntest du dir vorstellen, dass ich die Variable erst anlegen will?
>
> Was hält dich ab?

My Unwisse. long oder int, das ist die Frag, my Boy

von Falk B. (falk)


Lesenswert?

@Roth (Gast)

>Ich erkläre dann mal. Also ich will Pointer in Variablen speichern.
>Genau genommen Funktionspointer, also Pointer auf Funktionen.

Dazu muss man aber deren Größe nicht kennen. Man definiert einfach einen 
Funktionspointer, den Rest macht der Compiler.

>Zu Arduino-C: Könntze mir vorstellen, dass die Größe von Variablen mit
>der (max)Größe des Speichers/EEPROMS korreliert.

Nö, der korrelliert mit der CPU.

> Daher müsste es keinen
>Sinn machen, Pointern in einer relativ kleinen Welt 32 Bit zu
>spendieren.

>Aber meine Frage signalisiert mein Unwissen. Ich weiß nicht, wie groß
>der C-Compiler Pointer für die Arduino-Plattform macht. Daher die Frage.

Das Problem ist einfach, daß die Arduino-Plattform mehrere, recht 
verschiedene CPUs beinhaltet. Angefangen vom AVR mit 16 Bit Pointern, 
über dem SAM??? vom Arduino Due mit wahrscheinlich 32 Bit Pointern bis 
hin zu ESP & Co.

von Gerhard Z. (germel)


Lesenswert?

Soweit ich weiß gibt's Arduino inzwischen für 8, 16 und 32 Bitter mit 
stark unterschiedlichen Adressräumen. Da werden dann wohl auch die 
Pointergrößen, die C++ für die entsprechende Zielplattform generiert, 
unterschiedlich sein. Mit der Menge Info, mit der du aufwartest, lässt 
sich das also offensichtlich nicht entscheiden.

Gerhard

von Einer K. (Gast)


Lesenswert?

Roth schrieb:
> Arduino Fanboy D. schrieb:
>> Roth schrieb:
>>> Könntest du dir vorstellen, dass ich die Variable erst anlegen will?
>>
>> Was hält dich ab?
>
> My Unwisse. long oder int, das ist die Frag, my Boy

Wenn du einen Pointer anlegen willst, dann solltest du das auch tun!

1
using FunktionPointer = void(*)();
2
3
void testFunk()
4
{
5
  Serial.println("testFunk");
6
}
7
8
9
10
FunktionPointer testPtr = nullptr;
11
12
void setup() 
13
{
14
  Serial.begin(9600);      
15
  Serial.println("Start");
16
17
  testPtr = testFunk;
18
  testPtr();
19
20
  testPtr = [](){Serial.println("Lambda");};
21
  testPtr();
22
23
  Serial.print("sizeof(testPtr) : "); Serial.println(sizeof(testPtr));
24
  
25
}
26
27
void loop() 
28
{
29
30
}

von Klaus (Gast)


Lesenswert?

Hier ist mal ein Beispiel, wie das geht. Die Größe des Pointers kommt da 
nicht vor:

https://www.geeksforgeeks.org/function-pointer-in-c/

MfG Klaus

von Roth (Gast)


Lesenswert?

Ich kann es nicht fassen: Fanboy und ich haben zur selben Zeit ein 
Testprogramm gebaut.
1
long (*pDerPointer)();
2
3
void dieFunktion() {
4
  Serial.println("Hallo2");
5
}
6
7
void setup() {
8
  Serial.begin(9600);  
9
}
10
11
void loop() {
12
  pDerPointer = dieFunktion;  
13
  pDerPointer();
14
  delay(1000);
15
}

Das erste Wort meine ich. Hier long
1
long (*pDerPointer)();
Das funzt.

----

Mit int gehts auch:
1
int (*pDerPointer)();

----

Nur völlig suspekt ist das hier:
1
byte (*pDerPointer)();

Wieso geht ein byte als Pointer mit durch? Oder macht der Compiler was 
er will?

von Einer K. (Gast)


Lesenswert?

Roth schrieb:
> Wieso geht ein byte als Pointer mit durch?
Da doch eine Funktion einen Rückgabewert hat.
Und dessen Type bestimmst du damit.

Roth schrieb:
> Oder macht der Compiler was er will?
Der Compiler hält sich an die jeweils geltenden Standards.


Mache dich über Pointer kundig.
Ich rate dir dringend zu einem ca 1000 seitigen C++ Buch.

von Roth (Gast)


Lesenswert?

OK. Verstehen tue ich es nicht, aber es geht.
1
void (*pDerPointer)();
2
3
void dieFunktion() {
4
  Serial.println("Hallo 1");
5
}
6
7
void setup() {
8
  Serial.begin(9600);  
9
  delay(200);
10
  pDerPointer = dieFunktion;  
11
  pDerPointer();
12
  pDerPointer = [](){Serial.println("Hallo 2");};
13
  pDerPointer();
14
  pDerPointer = [](){Serial.println(sizeof(pDerPointer));};
15
  pDerPointer();
16
}
17
18
void loop() {
19
}

Die Konstruktion mit dem '[]' kannte ich z.B. überhaupt noch nicht.

Vielen Dank an alle. Insbesondere an meine lieben Freund den Arduino 
Fanboy :D (das meine ich jetzt ernst, hat mich gefreut)

von Roth (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Ich rate dir dringend zu einem ca 1000 seitigen C++ Buch.

So lange lebe ich am ende gar nicht mehr ;)

Ach so, den Pointer habe ich mit void angelegt. Comiler macht also was 
er will, wie meine Angestellten ... irgendwas mache ich falsch

von Roth (Gast)


Lesenswert?

Um das zu Ende zu bringen: So gehts auch.
1
void (*pDerPointer)();
2
3
void dieFunktion() {
4
  Serial.println("Hallo");
5
}
6
7
void mitPointerparameter(int p) {
8
  pDerPointer = p;  
9
  pDerPointer();
10
}
11
12
void setup() {
13
  Serial.begin(9600);  
14
  delay(300);
15
  mitPointerparameter(dieFunktion);
16
}
17
18
void loop() {
19
}

Allerdings gehts bei dem Parameter 'mitPointerparameter(int p)' nur mit 
int oder long . byte gibt nur 'Ha' aus, das 'llo' wird verschluckt. 
Verstehe das wer will ...

von Einer K. (Gast)


Lesenswert?

Roth schrieb:
> So lange lebe ich am ende gar nicht mehr ;)

Du verplemperst mehr Lebenszeit mit "im Nebel stochern".
Naja, wenn es dir Spass macht?



Roth schrieb:
> Verstehe das wer will ...
Du schlägst die Warnungen deines Compilers in den Wind, und beschwerst 
dich dann, dass er Mist baut?
Seltsame Vorstellungen du hast...

von Roth (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Du schlägst die Warnungen deines Compilers in den Wind, und beschwerst
> dich dann, dass er Mist baut?

Quatsch. Da kommen keine Warnungen. Ich bin blauäugig aber nicht blöd.

von Roth (Gast)


Lesenswert?

Außerdem gehts schon lange. Eine Interrupt-Routine, die zeitgesteuert 
beliebige Funktionen aufrufen können soll. Am meisten ärgert mich ja, 
dass Arduino Fanboy zur Lösung beigetragen hat ;) aber das Skript mit 
Using ist gut. Bin ja noch C-Anfänger, aber habe ich glatt in mein 
Repertoire übernommen. thx

von foobar (Gast)


Lesenswert?

> aber das Skript mit Using ist gut.

Exakt das gleiche bekommst du mit "typedef void (*FunktionPointer)();" 
und im Gegensatz zu dem Using-Statement (ein C++11-Feature) funktioniert 
das mit allen C und C++ Compilern.

Btw, was du anstellst nenn ich Voodoo-Programmierung - ohne Verständnis 
irgendwelche Codefragmente zusammenpappen und hoffen, dass irgendwas 
Lauffähiges bei rauskommt.

von foobar (Gast)


Lesenswert?

> Außerdem gehts schon lange. Eine Interrupt-Routine, die zeitgesteuert
> beliebige Funktionen aufrufen können soll.

Du hast nur noch nicht die Fehler gefunden ;-) An dem Problem haben sich 
schon gestandene C-Programmierer die Zähne ausgebissen.

von Rolf M. (rmagnus)


Lesenswert?

Roth schrieb:
> Aber meine Frage signalisiert mein Unwissen. Ich weiß nicht, wie groß
> der C-Compiler Pointer für die Arduino-Plattform macht. Daher die Frage.

Die Größe brauchst du gar nicht zu wissen, um einen solchen Zeiger zu 
erstellen. Die weiß der Compiler auch ohne dich.

Roth schrieb:
> Allerdings gehts bei dem Parameter 'mitPointerparameter(int p)' nur mit
> int oder long . byte gibt nur 'Ha' aus, das 'llo' wird verschluckt.
> Verstehe das wer will ...

Roth schrieb:
> Nur völlig suspekt ist das hier:byte (*pDerPointer)();
> Wieso geht ein byte als Pointer mit durch? Oder macht der Compiler was
> er will?

Roth schrieb:
> OK. Verstehen tue ich es nicht, aber es geht.

Roth schrieb:
> Arduino Fanboy D. schrieb:
>> Ich rate dir dringend zu einem ca 1000 seitigen C++ Buch.
>
> So lange lebe ich am ende gar nicht mehr ;)

Deine Aussagen zeigen, dass du keinerlei Idee hast, wie oder warum der 
Code funktioniert. Das ist ja erstmal nicht schlimm - letztendlich fängt 
ja jeder mal so an. Aber glaube mir: Mit einem Buch wirst du schneller 
sein, als mit deiner aktuellen Lernmethode. Das weiß ich aus eigener 
Erfahrung.

Roth schrieb:
> aber das Skript mit Using ist gut. Bin ja noch C-Anfänger, aber habe ich
> glatt in mein Repertoire übernommen. thx

Das ist kein C, sondern C++.

Roth schrieb:
> Arduino Fanboy D. schrieb:
>> Du schlägst die Warnungen deines Compilers in den Wind, und beschwerst
>> dich dann, dass er Mist baut?
>
> Quatsch. Da kommen keine Warnungen. Ich bin blauäugig aber nicht blöd.

Da müssten eigentlich viele Warnungen kommen, denn da passen überall die 
Typen nicht zusammen. Mich wundert, dass der Compiler das überhaupt 
akzeptiert. C++ ist da normalerweise ziemlich restriktiv.

von Peter D. (peda)


Lesenswert?

avr schrieb:
> Mit sizeof findest du die Größe heraus.
1
  return sizeof(void*);
2
  c0:  82 e0         ldi  r24, 0x02  ; 2
3
  c2:  08 95         ret

von Axel S. (a-za-z0-9)


Lesenswert?

Klaus schrieb:
> avr schrieb:
>> Mit sizeof findest du die Größe heraus.
>
> Was hilft es einem, wenn man das weiß?

Man muß dann keine dummen[*] Fragen mehr in ein Forum rotzen


[*] ok, vielleicht nicht direkt "dumm". Aber man kann die Antwort mit 
minimalem Aufwand selber herausfinden.

von Einer K. (Gast)


Angehängte Dateien:

Lesenswert?

Roth schrieb:
> Arduino Fanboy D. schrieb:
>> Du schlägst die Warnungen deines Compilers in den Wind, und beschwerst
>> dich dann, dass er Mist baut?
>
> Quatsch. Da kommen keine Warnungen. Ich bin blauäugig aber nicht blöd.

Du bist unglaublich borniert, wenn ich das mal so sagen darf.

Ich finde, lernende haben die Informationen aufzusaugen, wie ein 
Schwamm. So sollte es sein. Aber du bis wie Lotus. Alles was dir nicht 
schmeckt perlt einfach ab.

Siehe Anhang.

von fop (Gast)


Lesenswert?

Dazu würde ich sagen, ein Pointer ist so groß, wie es dem Programmierer 
des Compilers in den Kram passte. Was noch nicht mal bedeutet, dass er 
seine Meinung zu dem Thema nicht auch mal ändern könnte.

Und wenn jetzt der große Aufschrei kommt, dass er die Größe an die 
Zielarchitektur anpasst, gebe ich folgendes zu bedenken :
Wenn man es genau nimmt haben AVRs 3 Adressräume :
- Programmspeicher (Flash)
- RAM
- Daten EEPROM
Wobei ich gerade Teile mit bis zu 384k Programmspeicher und 32k Ram 
sehe. Also braucht es geschätzte 19 Bit, um eine Speicheradresse 
eindeutig zu adressieren. 24 Bit wären also eine ganz nette Größe.
AVR-GCC benutzt meines Wissens nach nur 16 Bit. Das kommt bestimmt auch 
daher, dass die AVRs mal mit 8k Programmspeicher angefangen haben. 
Ausserdem hat man versäumt die Adressbereiche sauber in den Pointern 
abzulegen, sondern hat seltsame Konstrukte gewählt, um beim Zugriff den 
Adressraum anzugeben.
Was also, wenn die Entwickler von AVR-GCC irgendwann mal einen Rappel 
kriegen und sagen, jetzt machen wir das mal richtig und ändern die Größe 
eines Pointers ?

Oder wenn Du Deinem Projekt WLAN bescheren möchtest und vom AVR zum ESP 
wechselst ?

Da gibt es nur eins : Schreibe am Besten keinen Code, der davon abhängig 
ist, wie der Compiler die Daten ablegt !

Ich sehe auch in dem Code, den der Fragesteller als Lösung akzeptiert 
hat keinen Zugriff, der die Länge eines Pointers kennen müsste, ausser 
dass die Länge in Bytes ausgegeben wird.

von Roth (Gast)


Lesenswert?

Rolf M. schrieb:

> Die Größe brauchst du gar nicht zu wissen, um einen solchen Zeiger zu
> erstellen. Die weiß der Compiler auch ohne dich.

Normal muss man schon wissen, wie groß eine Variable sein soll, wenn man 
sie anlegt (long, int, ...). Woher soll ich wissen, dass bei Pointern 
der Comiler den Datentyp ignoriert und selbst festlegt? Sogar ein void 
ging ja. Ich komme aus einer anderen Programmierecke (VB, Assembler, 
SQL). Mit C/C++ habe ich keine praktische Erfahrung, man mann ja nicht 
alles gleichzeitig tun.

foobar schrieb:
> Exakt das gleiche bekommst du mit "typedef void (*FunktionPointer)();"
> und im Gegensatz zu dem Using-Statement (ein C++11-Feature) funktioniert
> das mit allen C und C++ Compilern.

Danke. Hier in diesem Forum kann man viel lernen.

foobar schrieb:
> Btw, was du anstellst nenn ich Voodoo-Programmierung - ohne Verständnis
> irgendwelche Codefragmente zusammenpappen und hoffen, dass irgendwas
> Lauffähiges bei rauskommt.

Ich versuche plumpes abschreiben zu vermeiden. Aber manchmal ist es eben 
so, wenn man in einem drin Projekt ist, da fehlt die Zeit für die Basics 
und dann muss learning by doing her. OK, ich habe noch ein paar Löcher 
in C, aber die werden sich schließen, wenn ich öfter in C arbeite. 
Aktuell bin ich am allerersten Programm.

foobar schrieb:
> Du hast nur noch nicht die Fehler gefunden ;-) An dem Problem haben sich
> schon gestandene C-Programmierer die Zähne ausgebissen.

hähä. Ich habe ja selbst nicht geglaubt, aber es funktionierte sogar auf 
Anhieb. Natürlich nur wegen eurer tollen Hilfe.

von Marco H. (damarco)


Lesenswert?

Die Größe des Pointers hängt ausschließlich mit der Architektur 
zusammen.

Beim AVR oder ARM kann man von 16bit bzw. 32Bit ausgehen. Auf einem PC 
wird die Sache schon schwieriger, Long, Long Long ... usw..32bit oder 
64bit Architektur..

von A. S. (Gast)


Lesenswert?

Marco H. schrieb:
> Die Größe des Pointers hängt ausschließlich mit der Architektur
> zusammen.

Nein. Das wurde hier erläutert:

fop schrieb:
> Dazu würde ich sagen, ein Pointer ist so groß, wie es dem Programmierer
> des Compilers in den Kram passte. Was noch nicht mal bedeutet, dass er
> seine Meinung zu dem Thema nicht auch mal ändern könnte.

Der Programmierer des Compilers kennt ja in der Regel die Architektur 
und macht dann was sinnvolles. Aber ob es im Grenzfall 2,3 oder 4 Byte 
sind, und ob noch ein paar Bits zwischen Flash und RAM unterscheiden 
oder auch EEPROM mit berücksichtigen, ... das macht er, wie er will.

von Marco H. (damarco)


Lesenswert?

Ja das mag sein...

von Dr. Sommer (Gast)


Lesenswert?

Das ist das schöne an z.B. ARM: Da sind Flash, EEPROM, RAM, Peripherie, 
externes RAM, usw. alle in einem großen 32bit-Adressraum. Dadurch kann 
man alles einheitlich mit einem 32bit-Zeiger adressieren, welche von der 
32bit-Architektur natürlich effizient verarbeitet werden.

von Harry L. (mysth)


Lesenswert?

Dr. Sommer schrieb:
> Das ist das schöne an z.B. ARM: Da sind Flash, EEPROM, RAM, Peripherie,
> externes RAM, usw. alle in einem großen 32bit-Adressraum. Dadurch kann
> man alles einheitlich mit einem 32bit-Zeiger adressieren, welche von der
> 32bit-Architektur natürlich effizient verarbeitet werden.

Du vergleichst Äpfel mit Birnen - bzw. Harvard- mit von 
Neumann-Architektur.

Den Unterschied sollte man schon verstehen.
Bei Harvard-Architektur gibt es physikalisch getrennte Adressräume für 
Code und Daten.

* AVR-8bit ist Harvard-Architektur.
* ARM ist von Neumann-Architektur

von Rolf M. (rmagnus)


Lesenswert?

Roth schrieb:
> Normal muss man schon wissen, wie groß eine Variable sein soll, wenn man
> sie anlegt (long, int, ...).

Nein. Wenn du einen long definierst, ist das eine Variable vom Typ long, 
und fertig. Eine Größe gibt man da nicht an.

> Woher soll ich wissen, dass bei Pointern der Comiler den Datentyp
> ignoriert und selbst festlegt?

Er ignoriert gar nichts. Du hast nur nicht verstanden, wie Pointer 
funktionieren. Und genau solche Grundlagen lassen sich am besten einem 
Buch oder Tutorial entnehmen. Das alles durch trial & error und 
Interpretation dessen, wie der Compiler reagiert, zu erlernen, ist 
ziemlich aussichtslos.

> Sogar ein void ging ja.

Ja, weil das void überhaupt nichts mit der Größe des Zeigers zu tun hat. 
Wenn du einen long* definierst, ist das ein Zeiger auf einen long. 
Welche Größe der Zeiger selber hat, ist davon unabhängig. Ein void* ist 
ein Zeiger auf etwas, das an dieser Stelle nicht weiter definiert ist. 
Auch hier hat das nichts mit der Größe des Zeigers zu tun.

> foobar schrieb:
>> Btw, was du anstellst nenn ich Voodoo-Programmierung - ohne Verständnis
>> irgendwelche Codefragmente zusammenpappen und hoffen, dass irgendwas
>> Lauffähiges bei rauskommt.
>
> Ich versuche plumpes abschreiben zu vermeiden. Aber manchmal ist es eben
> so, wenn man in einem drin Projekt ist, da fehlt die Zeit für die Basics
> und dann muss learning by doing her. OK, ich habe noch ein paar Löcher
> in C, aber die werden sich schließen, wenn ich öfter in C arbeite.

Ich fürchte, das sind ein paar ziemlich große Löcher. Wenn du das lernen 
willst, indem du einfach in C arbeitest, könnten die schlimmsten dieser 
Löcher sich in einigen Jahren verkleinert haben. Wie schon oben 
geschrieben: Ich kenne das aus persönlicher Erfahrung und würde 
niemandem empfehlen, das genauso ineffizient zu machen wie ich damals.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Roth schrieb:
> Das erste Wort meine ich. Hier long
> long (*pDerPointer)();

Das long ist nicht die Größe des Pointers, sondern die Angabe, welchen 
Typ die Funktion, wenn Du sie über den Pointer aufrufst, 
zurückliefert.

Schreibe also statt long den Typ hin, welchen die Funktion 
zurückliefert. Wenn sie keinen zurückliefert, dann void.

Hauptsache, das passt zusammen. Sonst erlebst Du mit etwaigen 
Rückgabewerten Dein blaues Wunder.

von R. M. (rmax)


Lesenswert?

Roth schrieb:

> Normal muss man schon wissen, wie groß eine Variable sein soll, wenn man
> sie anlegt (long, int, ...). Woher soll ich wissen, dass bei Pointern
> der Comiler den Datentyp ignoriert und selbst festlegt?

Ich denke, ich habe Dein Verständnisproblem verstanden. ;)

Es geht hier nicht um Pointer im allgemeinen, sondern speziell um 
Funktionspointer. Der Datentyp, von dem Du meinst, er werde ignoriert, 
gibt nicht die Größe des Pointers an, sondern das ist der Datentyp, den 
die Funktion zurückgibt, auf die der Pointer zeigen kann.
1
void (*funcptr1)(void)

Ist ein Zeiger auf eine Funktion, die keinen Aufrufparameter und keinen 
Rückgabewert hat.
1
char (*funcptr2)(int)

Ist ein Zeiger auf eine Funktion, die mit einem int-Parameter aufgerufen 
wird und einen char-Wert zurückgibt.

Die Größe des Pointers selbst (also die Größe Adresse der aufzurufenden 
Funktion) ist in beiden Fällen gleich.

Versuchst Du, die Adresse einer Funktion einem Pointer mit anderer 
Signatur (Aufruf- und Rückgabetypen) zuzuweisen, bekommst Du eine 
Compilerwarnung (vorausgesetzt Warnungen sind aktiviert).

Ergänzung: Auch bei Daten-Pointern ist es so, dass der angegebene Typ 
nicht die Pointergröße ist, sondern die Größe des Datentyps auf den der 
Pointer zeigen kann.

: Bearbeitet durch User
von fop (Gast)


Lesenswert?

Hier gehen jetzt zwei Dinge durcheinander. Die Größe eines Pointers und 
die Größe dessen, auf was er zeigt.

Für das zweite gibst Du ja den Typ an, auf den der Pointer zeigt. Wenn 
Du dafür jetzt noch die Typen aus der stdint.h nutzt, weißt Du es 
ziemlich genau.

von Joachim B. (jar)


Lesenswert?

fop schrieb:
> AVR-GCC benutzt meines Wissens nach nur 16 Bit.

und dann klemmte es als der ATmega2560 und ATmega 1284p kam, es wurd 
flugs ein drittes Adressbyte nachbestellt!

Ich wunderte mich in den Anfangszeiten über keinen Zugriff oberhalb 64K 
beim m2560, mit dem m1284p lernte ich dann dazu.

von (prx) A. K. (prx)


Lesenswert?

Vielleicht hilft es: Seit C99 kann es in stdint.h die optionalen 
typedefs intptr_t und/oder uintptr_t geben, die einem Integer-Typ 
entsprechen, der einen void* Pointer aufnehmen kann.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

fop schrieb:

> Und wenn jetzt der große Aufschrei kommt, dass er die Größe an die
> Zielarchitektur anpasst, gebe ich folgendes zu bedenken :
> Wenn man es genau nimmt haben AVRs 3 Adressräume :
> - Programmspeicher (Flash)
> - RAM
> - Daten EEPROM

Nö, entweder man legt es "eng" aus, dann haben die AVR8 vier 
Adressräume, nämlich Flash, RAM, REGS und SFR. Der EEPROM hat bei dieser 
Betrachtungsweise allerdings überhaupt keinen eigenen Adressraum, der 
ist eine reine Fiktion des C-Compilers. Außerdem zerfällt der 
SFR-Bereich, genau genommen, auch noch in zwei Teile...

Oder man legt es "weit" aus, dann gibt zwar den EEPROM-Raum, aber auch 
noch sehr viel mehr Adressräume beim AVR8 (als Subräume der o.g.), mit 
deren vollem Umfang allerdings jeder existierende C-Compiler 
hoffnungslos überfordert ist. Der Nutzer hat viele Aspekte dieses Zeugs 
selber zu kontrollieren, typischerweise über Linker-Scripts.

Und zusätzlich: egal ob weit oder eng: Die Adressierung kann mehrdeutig 
sein. Schon in der "engen" Betrachtung überlappen REGS/RAM (allerdings 
nicht bei den ATXmega) und SFR/RAM. Besonders schlechte Voraussetzungen 
für die Grundkonzepte eines C-Compilers, der kommt ja schon ganz 
grundsätzlich mit mit mehreren Adressräumen nicht wirklich klar...

> Da gibt es nur eins : Schreibe am Besten keinen Code, der davon abhängig
> ist, wie der Compiler die Daten ablegt !

Noch besser: mach' dich erst garnicht von den Furzen eines Compilers 
abhängig, sondern rede mit dem Device in der einzigen Sprache, die es 
ganz sicher immer korrekt versteht! Asm rules...

von fop (Gast)


Lesenswert?

Bei Zeigern auf Funktionen gibt es ja noch mehr Größen :
- Größe des Zeigers
- Größe des Programmcodes der Funktion
- Größe des Rückgabewertes
- Größen der Aufrufparameter

Punkt 2 ist wieder vom Umfang Deiner Funktion, dem Compiler und diversen 
Optimierungsoptionen sowie der Zielhardware abhängig. Das gute daran : 
so lange noch genug Platz im Programmspeicher vorhanden ist, braucht 
Dich diese Angabe nicht kümmern.

Die letzten beiden Punkte gibst Du wieder an, wenn Du den Typ des 
Zeigers festlegst.

Jetzt mal ungetestet einfach so hingetippt :
1
uint8_t (*pDerPointer)(uint16_t ersterParameter, uint32_t zweiterParameter);
sollte einen Zeiger auf eine Funktion anlegen, die 8 Bit zurück gibt, 
die genau 2 Parameter erwartet, deren erster Parameter 16 Bit groß ist 
und deren 2. Parameter 32 Bit groß ist.
Du solltest peinlich genau darauf achten, dass alle Funktionen, deren 
Verweis Du in diesen Pointer lädst, diese Bedingungen erfüllen !

Wenn Du jetzt sagst, ich mag aber ganz unterschiedliche Funktionen mit 
ganz unterschiedlichen Parametern über so einen / so ein Array von 
Pointer(n) referenzieren sage ich : Ja - Nee - is klar...
Weil bei mir ist nur angekommen : Jetzt will ich das Chaos auf die 
Spitze treiben.
Als Anfänger würde ich Dir vorschlagen, nur die gemeinsamen Werte als 
Parameter zu übergeben, und die unterschiedlichen Dir innerhalb der über 
Pointer aufgerufenen Funktionen per Aufruf von Funktionen besorgen zu 
lassen.

von fop (Gast)


Lesenswert?

c-hater schrieb:
> Noch besser: mach' dich erst garnicht von den Furzen eines Compilers
> abhängig, sondern rede mit dem Device in der einzigen Sprache, die es
> ganz sicher immer korrekt versteht! Asm rules...

Was es aber mitnichten einfacher macht die Prozessorarchitektur zu 
wechseln.

von c-hater (Gast)


Lesenswert?

fop schrieb:

> c-hater schrieb:
>> Noch besser: mach' dich erst garnicht von den Furzen eines Compilers
>> abhängig, sondern rede mit dem Device in der einzigen Sprache, die es
>> ganz sicher immer korrekt versteht! Asm rules...
>
> Was es aber mitnichten einfacher macht die Prozessorarchitektur zu
> wechseln.

Natürlich nicht.

Der Punkt ist: es macht es aber auch nicht schwerer. Solange man 
nämlich direkt mit der Hardware hakelt, sind alle C-Versprechen zur 
"Portabilität" sowieso nur eins: reine Lügen.

von Roth (Gast)


Lesenswert?

Rolf M. schrieb:
> Ich fürchte, das sind ein paar ziemlich große Löcher. Wenn du das lernen
> willst, indem du einfach in C arbeitest, könnten die schlimmsten dieser
> Löcher sich in einigen Jahren verkleinert haben. Wie schon oben
> geschrieben: Ich kenne das aus persönlicher Erfahrung und würde
> niemandem empfehlen, das genauso ineffizient zu machen wie ich damals.

Ja meinetwegen sieht das so aus. Allerdings lassen sich mit großen 
Defiziten auch keine großen Sprünge machen. Das Quereinsteigertum 
(betrachte mich als solchen) bringt es so mit sich, Lücken auch schon 
mal in Basics zu haben. Es fehlt ja die fundierte Ausbildung, und das 
ist eben so.

> Ja, weil das void überhaupt nichts mit der Größe des Zeigers zu tun hat.
> Wenn du einen long* definierst, ist das ein Zeiger auf einen long.
> Welche Größe der Zeiger selber hat, ist davon unabhängig. Ein void* ist
> ein Zeiger auf etwas, das an dieser Stelle nicht weiter definiert ist.
> Auch hier hat das nichts mit der Größe des Zeigers zu tun.

So siehste, genau das war es jetzt. Unabhängig vom Datentyp wird IMMER 
ein Pointer gespeichert. Ich habe mich offenbar nicht deutlich 
ausgedrückt. In VB/VBA z.B. stellen sich solche Fragen gar nicht, und in 
SQL schon gar nicht. Aber reden wir mal von Assembler. Für eine Variable 
reserviere ich Platz. Für ein Byte 1 Byte, für ein Integer 2 Byte usw. 
Und daher habe ich gefragt, wieviel Platz ein Pointer benötigt, weil ich 
den als long oder int anlegen wollte. Für mich ist ein Pointer einfach 
nur ein 16- oder 32-Bit Wert, der in einer entsprechend großen 
Speicherstelle abgelegt werden muss. Dazu dachte ich an die Variable und 
übersah, dass C/C++ Variablen eh nur als Pointer referenziert und es 
daher egal ist, wie groß der Datentyp ist und warum auch void 
funktioniert. Das sind Eigenarten der Softwarearchitektur, die ich 
leider erst kapieren muss, und die ich noch nicht mal in Assembler so 
hatte. Feste Zeigeradressen waren in ASM letztendlich nur Präprozessor- 
oder Parserangelegenheiten, die dann irgendwann hardcodiert im Code 
standen.

Sehr gut, wieder was dazugelernt.

von Roth (Gast)


Lesenswert?

So, jetzt habe ich alles durchgelesen. Ihr habt euch alle mächtig ins 
Zeug gelegt, danke danke danke  :-) Ich mus es nochmal sagen, ein 
wirklich tolles Forum mit genau so qalifizierten wie hilfsbereiten 
Mitgliedern. Sowas ist heute selten und es freut mich, dass es das noch 
gibt.

LG

von Stefan F. (Gast)


Lesenswert?

Ich empfehle, alle Compiler Warnung mit der Compiler-Option -Wall zu 
aktivieren. Als Editor/IDE empfehle ich QT-Creator, weil dieses eine 
große Menge zusätzliche Kontrollen durchführt und auf mögliche Probleme 
hinweist.

von (prx) A. K. (prx)


Lesenswert?

Roth schrieb:
> Und daher habe ich gefragt, wieviel Platz ein Pointer benötigt, weil ich
> den als long oder int anlegen wollte.

Dafür lassen sich besagte (u)intptr_t Typen gebrauchen.

von Wolfgang (Gast)


Lesenswert?

Roth schrieb:
> Woher soll ich wissen, dass bei Pointern
> der Comiler den Datentyp ignoriert und selbst festlegt?

Ein Pointer zeigt auf eine Speicherstelle, an der eine Variable steht. 
Welchen Typ diese Variable hat, ist für die Größe des Pointers völlig 
egal.

von Joachim B. (jar)


Lesenswert?

Wolfgang schrieb:
> Ein Pointer zeigt auf eine Speicherstelle, an der eine Variable steht.
> Welchen Typ diese Variable hat, ist für die Größe des Pointers völlig
> egal.

den Satz verstehe ich nicht mal, für mich war ein Pointer ein Zeiger auf 
eine Variable, also eine Adresse im Speicher.

Wenn die Adresse mit 16-bit erreicht werden kann dann sind das 2 Byte a 
8 Bit, aber wenn die Adresse den 64K Adressraum übersteigt braucht mein 
Pointer 3 Byte oder gar 4 Byte oder in 64-Bit Versionen sogar 8 Byte, 
also verstehe ich nur das Pointer zwischen 16-64 Bit lang sein können.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Das wäre theoretisch denkbar. Ich kenne aber keine CPU und keinen 
Compiler, die das so flexibel handhaben.

von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> Wenn die Adresse mit 16-bit erreicht werden kann dann sind das 2 Byte a
> 8 Bit, aber wenn die Adresse den 64K Adressraum übersteigt braucht mein
> Pointer 3 Byte oder gar 4 Byte oder in 64-Bit Versopnen sogar 8 Byte,

Naja...
Ganz so einfach ist es nicht.
Der ATMega2560 hat  auch nur 2 Byte breite function pointer.
Trotz 256k Flash
Stichwort: trampolines

von Joachim B. (jar)


Lesenswert?

Arduino Fanboy D. schrieb:
> Ganz so einfach ist es nicht.
> Der ATMega2560 hat  auch nur 2 Byte breite function pointer.

und was war mit der Adresserweiterung aufs dritte Byte, ich bekomme es 
gerade nicht zusammen war das ES Register?

gefunden
Beitrag "Re: ATmega2560 Adressraum Pages"

und folgende

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Stefanus F. schrieb:
> Das wäre theoretisch denkbar. Ich kenne aber keine CPU und keinen
> Compiler, die das so flexibel handhaben.

Fairchilds F9445: Der Speicher umfasste in einem seiner beiden Modi 64k 
16-Bit Worte. Worte wurden mit 16-Bit Wortadressen angesprochen, Bytes 
indes mit 17-Bit Byteadressen.

Weniger altertümlich: Maxims MaxQ2000 Microcontroller. Worte werden mit 
Wortadressen, Bytes mit Byteadressen adressiert. Gleiches Problem, 
andere Lösung: An die obere Hälfte eines 64kW Adressraums kommt man nur 
wortweise ran.

Bei den Renesas M16C Mikrocontrollern gibt es einen 64kB 
Datenadressraum, der in einem 1MB Adressraum eingebettet ist. Es handelt 
sich also nicht um getrennte Adressräume. Konstanten im ROM lassen sich 
nur mit 20-Bit Adressen ansprechen, für Variablen im RAM jedoch reichen 
16-Bit Adressen. Wer immer sowas erfindet, an C kann er dabei nicht 
gedacht haben.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> und was war mit der Adresserweiterung aufs dritte Byte, ich bekomme es
> gerade nicht zusammen war das ES Register?
>
> gefunden
> Beitrag "Re: ATmega2560 Adressraum Pages"
>
> und folgende
Hier dreht es sich um Function Pointer, da sieht die Sache noch etwas 
anders aus. Da wird noch eine verborgene Extrarunde gedreht.
Suche mal nach "avr trampolin section"

von Marco H. (damarco)


Lesenswert?

ich werfe mal noch was in die Runde. In AVR oder ARM Code sieht man 
häufig das int pointer auf Funktionen zeigen... Genau um solche 
Konstrukte ging es hier... Deshalb die Frage nach der Größe.. Die Frage 
lässt sich vermeiden wenn man es richtig macht ;)

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Marco H. (damarco)

>Konstrukte ging es hier... Deshalb die Frage nach der Größe.. Die Frage
>lässt sich vermeiden wenn man es richtig macht ;)

Oder wie es immer heißt.

Es kommt nicht auf die Größe an. ;-)

(Wer's glaubt, wird seelig)

von Joachim B. (jar)


Lesenswert?

Arduino Fanboy D. schrieb:
> Hier dreht es sich um Function Pointer

ähm, ich verstehe deinen Einwand nicht Function Pointer sind auch nur 
Zeiger oder Adressen und da sie ja auch ausserhalb von 16 Bit liegen 
können müssen mehr als 2 Byte mitspielen.

Als ich die Arduino fastLED LIB zum ersten Mal auf dem 1284p statt 328p 
nutze klappte nichts mehr, im Oszi sah ich das die Zugriffslänge von 
einem Farbklecks statt 30µs nun 10% länger dauerte dauerte, das dritte 
Adressbyte war wohl Schuld

Beitrag "Arduino FastLED LIB vs. WS28xx LIB"
https://www.mikrocontroller.net/attachment/244099/m1284p_timing.jpg

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Marco H. schrieb:
> In AVR oder ARM Code sieht man häufig das int pointer auf Funktionen
> zeigen...

Das sieht man nur in sehr, sehr grindigem Code, der aus steinalten 
K&R-Zeiten stammt.

So etwas wird seit Beginn der 90er Jahre nicht mehr geschrieben; könnte 
es sein, daß Du da einfach etwas missverstehst?

Zeig' doch mal so ein Stück "AVR oder ARM Code", der solch einen 
int-Pointer enthalten soll.

von Carl D. (jcw2)


Lesenswert?

Joachim B. schrieb:
> Arduino Fanboy D. schrieb:
>> Hier dreht es sich um Function Pointer
>
> ähm, ich verstehe deinen Einwand nicht Function Pointer sind auch nur
> Zeiger oder Adressen und da sie ja auch ausserhalb von 16 Bit liegen
> können müssen mehr als 2 Byte mitspielen.
>
> Als ich die Arduino fastLED LIB zum ersten Mal auf dem 1284p statt 328p
> nutze klappte nichts mehr, im Oszi sah ich das die Zugriffslänge von
> einem Farbklecks statt 30µs nun 10% länger dauerte dauerte, das dritte
> Adressbyte war wohl Schuld
>
> Beitrag "Arduino FastLED LIB vs. WS28xx LIB"
> https://www.mikrocontroller.net/attachment/244099/m1284p_timing.jpg

Die Function Pointer sind beim AVR immer 16bit lang. Damit erreicht man 
entweder Funktionen innerhalb der erste 64k Worte, oder speziell dafür 
erzeugte Sprungbefehle in den Bereich >64k Worte, die "Trampoline" 
genannt werden und ganz vorne im Code angesiedelt werden. Sie sind mit 
16bit-Function-Pointern immer erreichbar (nur dauert der extra Sprung 
etwas).

von Axel S. (a-za-z0-9)


Lesenswert?

Roth schrieb:
> Rolf M. schrieb:
>> Ja, weil das void überhaupt nichts mit der Größe des Zeigers zu tun hat.
>> Wenn du einen long* definierst, ist das ein Zeiger auf einen long.
>> Welche Größe der Zeiger selber hat, ist davon unabhängig. Ein void* ist
>> ein Zeiger auf etwas, das an dieser Stelle nicht weiter definiert ist.
>> Auch hier hat das nichts mit der Größe des Zeigers zu tun.
>
> So siehste, genau das war es jetzt. Unabhängig vom Datentyp wird IMMER
> ein Pointer gespeichert.

Meine Güte, wie merkbefreit kann man sein? "Pointer" allein ist kein 
Datentyp. "Pointer auf long" ist das. Und ein Pointer auf long ist etwas 
anderes als ein Pointer auf char oder Pointer auf float oder auch ein 
void Pointer. Der Compiler "vergißt" hier gar nichts. Er legt einen 
Pointer von eben jenem Typ an, den du per Programm verlangt hast.

> Ich habe mich offenbar nicht deutlich ausgedrückt.

Du hast vor allem keine Ahnung. Und - was schlimmer ist - scheinbar auch 
keine Absicht, daran etwas zu ändern. Sonst hättest du all das, was wir 
dir schreiben, schon in einem Buch über C gelesen.

> Aber reden wir mal von Assembler. Für eine Variable
> reserviere ich Platz. Für ein Byte 1 Byte, für ein Integer 2 Byte usw.

Und schon wieder falsch. Integer ist kein Konzept von Assembler. Das ist 
ein Konzept von C. Und auch in C ist ein Integer nicht zwangsweise 2 
Byte lang. Da ist noch nicht mal ein Byte immer 8 Bits lang.

> Und daher habe ich gefragt, wieviel Platz ein Pointer benötigt

Pointer sind auch kein Konzept von Assembler. Das äquivalente Konzept in 
Assembler heißt Adresse. Es ist aber viel weniger abstrakt als ein 
Pointer. Bspw. kannst du eine Adresse in Assembler immer nur in 
Einerschritten inkrementieren. Der Inkrement-Operator in C hingegen 
erhöht den "Wert" des Pointers um die Größe des Datentyps, auf den der 
Pointer zeigt.

> Für mich ist ein Pointer einfach nur ein 16- oder 32-Bit Wert

Und das ist im Kontext von C schlicht falsch

> übersah, dass C/C++ Variablen eh nur als Pointer referenziert

Häh?

> und es
> daher egal ist, wie groß der Datentyp ist und warum auch void
> funktioniert.

Ich glaube du hast nichts davon begriffen.

> Das sind Eigenarten der Softwarearchitektur, die ich
> leider erst kapieren muss

Das ist eine schöne Einsicht. Es wäre toll wenn du daraus auch mal 
Schlußfolgerungen ziehen würdest. C ist nicht Assembler.

von noreply@noreply.com (Gast)


Lesenswert?

Laßt den Compiler seine Arbeit machen und casted ordentlich.

von Alex G. (dragongamer)


Lesenswert?

Stefanus F. schrieb:
> Das wäre theoretisch denkbar. Ich kenne aber keine CPU und keinen
> Compiler, die das so flexibel handhaben.
Das würde auch die Idee, dem Nutzer Memory-Management durch pointer zu 
ermöglichen, ad absurdum führen, denn du könntest dann pointer nicht 
mehr sinnvoll inkrementieren weil der nächste Pointer könnte ja mehr Bit 
brauchen...


Theoretisch könnte man das aber für die binary einer höheren 
Programmiersprache (die keine direkten pointer anbietet) machen. Z.B. 
für Go oder Rust. Mit letzterem wird ja immerhin auf uCs experimentiert.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> ähm, ich verstehe deinen Einwand nicht Function Pointer sind auch nur
> Zeiger oder Adressen und da sie ja auch ausserhalb von 16 Bit liegen
> können müssen mehr als 2 Byte mitspielen.
Ich sehe, dass du das nicht verstehst...
Das kommt noch...
Die Adresse ist übrigens bis zu 22 Bit breit beim (x)AVR

ATMega2560: (z.B. Arduino Mega)
16Bit breite Funkionszeiger für einen 128kWort(256kByte) 
Adressbereich/Flash.
Das ist Fakt.
Unabwendbar.
Der Widerspruch wird mit Hilfe von trampolines aufgelöst.

Teste es...
Schau dir den generierten ASM Code an.
Suche die Trampolin Section.
Und dann wird es dir wie Schuppen in die Augen fallen.

von (prx) A. K. (prx)


Lesenswert?

Die Breite verschiedenartiger Pointer ist nicht ausschliesslich von 
Maschine oder Sprache beeinflusst, sondern kann auch auf Einschränkungen 
des Compilers zurück gehen.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Joachim B. schrieb:
> Arduino Fanboy D. schrieb:
>> Hier dreht es sich um Function Pointer
>
> ähm, ich verstehe deinen Einwand nicht Function Pointer sind auch nur
> Zeiger oder Adressen und da sie ja auch ausserhalb von 16 Bit liegen
> können müssen mehr als 2 Byte mitspielen.

Nicht zwingend. Es wurde schon mehrfach auf Trampolines hingewiesen.

Alex G. schrieb:
> Stefanus F. schrieb:
>> Das wäre theoretisch denkbar. Ich kenne aber keine CPU und keinen
>> Compiler, die das so flexibel handhaben.
> Das würde auch die Idee, dem Nutzer Memory-Management durch pointer zu
> ermöglichen, ad absurdum führen, denn du könntest dann pointer nicht
> mehr sinnvoll inkrementieren weil der nächste Pointer könnte ja mehr Bit
> brauchen...

Und man bräuchte dann für jede Größe einen anderen Zeigertypen. Gegeben 
hat es was derartiges mal unter DOS. Da gab es je nach genutztem 
Memory-Modell einen near-Pointer, der nur innerhalb eines 64k-Segments 
zugreifen konnte und einen far-Pointer, der an den ganzen Speicher ran 
kam.

von Marco H. (damarco)


Lesenswert?


von my2ct (Gast)


Lesenswert?

Axel S. schrieb:
> Meine Güte, wie merkbefreit kann man sein? "Pointer" allein ist kein
> Datentyp. "Pointer auf long" ist das. Und ein Pointer auf long ist etwas
> anderes als ein Pointer auf char oder Pointer auf float oder auch ein
> void Pointer.

Es ging um die Größe eines Pointers und die ist unabhängig davon, auf 
was für einen Variablentyp der Pointer zeigt.
Bei Pointer auf <Irgendwas> bekommt der Compiler eine Zusatzinformation 
über die Variable, z.B. um beim Inkrement die entsprechende Schrittweite 
zu kennen.

von Joachim B. (jar)


Lesenswert?

Rolf M. schrieb:
> Nicht zwingend. Es wurde schon mehrfach auf Trampolines hingewiesen.

habe gerade mal geschaut:
"A little more on the issue: GCC pointers - of all types - are only 
16-bits in length. That means you can address up to 128KB of FLASH 
memory directly with them, since FLASH is addressed as a number of 
16-bit words and not bytes like SRAM."

However, that means that they cannot address data or functions located 
above 128KB of FLASH space. A few 8-bit AVRs have 256KB of FLASH, so 
this means we need a way to address the higher flash segment when we 
perform an indirect function call. The solution is this automatically 
generated "trampoline" section which contains code needed to call the 
higher addresses. When your code needs to get above the 128KB barrier 
via an indirect function call, it instead "bounces" up to the desired 
location via the code in the trampoline section."

nun hat aber ein ATmega 1284p genau 128K flash nicht mehr! also hätte 
ich den Zugriff genau wie beim m328p erwartet und nicht langsamer.

Beim m2560 verstehe ich das.

Beitrag #5605945 wurde vom Autor gelöscht.
von Axel S. (a-za-z0-9)


Lesenswert?

my2ct schrieb:
> Axel S. schrieb:
>> Meine Güte, wie merkbefreit kann man sein? "Pointer" allein ist kein
>> Datentyp. "Pointer auf long" ist das. Und ein Pointer auf long ist etwas
>> anderes als ein Pointer auf char oder Pointer auf float oder auch ein
>> void Pointer.
>
> Es ging um die Größe eines Pointers und die ist unabhängig davon, auf
> was für einen Variablentyp der Pointer zeigt.

Es dürfte dir schwer werden, das allgemeingültig zu beweisen. Zumindest 
der C-Standard gibt das nicht her. Du machst hier den gleichen Fehler 
wie der TE, das Konzept "Pointer" in C mit dem Konzept "Adresse" auf 
Maschinenebene gleichzusetzen. Aber das ist falsch. Es sind weitgehend 
äquivalente Konzepte. Aber eben nicht das Gleiche.

> Bei Pointer auf <Irgendwas> bekommt der Compiler eine Zusatzinformation
> über die Variable, z.B. um beim Inkrement die entsprechende Schrittweite
> zu kennen.

Das ist nur ein Punkt, in dem ein Pointer mehr Information enthält als 
eine Adresse. Ein anderer Punkt wäre der Adreßraum, in dem der Pointer 
gilt. Schon avr-gcc kennt neben Pointern auf RAM auch Pointer auf Flash 
und Pointer auf EEPROM. Auf anderen Architekturen mag es noch weitere 
Adreßräume geben, durchaus auch mit sehr unterschiedlicher Größe. Es 
gibt genau gar keinen Grund, warum der C-Compiler dann Pointer auf 
unterschiedliche Adreßräume nicht auch mit unterschiedlicher Größe 
codieren dürfte.

In der Praxis wird es in 99% der Fälle so sein, daß alle Pointer gleich 
groß sind. Aber es gibt keine Garantie dafür.


Joachim B. schrieb:
> habe gerade mal geschaut:
> "A little more on the issue: GCC pointers - of all types - are only
> 16-bits in length. ..."

Aufpassen! Das ist eine Aussage über diese eine Implementierung mit 
dem Namen avr-gcc. Es ist keine allgemeingültige Aussage über gcc (den 
gibts auch für viele weitere Architekturen) oder gar über noch andere 
C-Compiler.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Axel S. schrieb:
> Das ist nur ein Punkt, in dem ein Pointer mehr Information enthält als
> eine Adresse. Ein anderer Punkt wäre der Adreßraum, in dem der Pointer
> gilt. Schon avr-gcc kennt neben Pointern auf RAM auch Pointer auf Flash
> und Pointer auf EEPROM. Auf anderen Architekturen mag es noch weitere
> Adreßräume geben, durchaus auch mit sehr unterschiedlicher Größe. Es
> gibt genau gar keinen Grund, warum der C-Compiler dann Pointer auf
> unterschiedliche Adreßräume nicht auch mit unterschiedlicher Größe
> codieren dürfte.

Doch, den gibt es. Schließlich weiß C nichts von Adressräumen. Und ein 
int* hat eine statisch zur Compilezeit festgelegte Größe. Es gibt keine 
Zeiger auf "int in Adressraum X" oder sowsas.
Der Compiler könnte also höchstens verschiedene Datentypen in getrennten 
Adressräumen unterbringen (also einer für short, einer für int u.s.w.). 
Das wäre aber eher ungewöhnlich. Und es muss dennoch möglich sein, jeden 
beliebigen Datenzeiger verlustlos in einen void* und zurück zu 
konvertieren, und diesen void* z.B. zu verwenden, um per memcpy die 
Daten umher zu kopieren.
Einzig die Unterscheidung zwischen Code und Daten gibt es. In C sind 
Funktionszeiger nicht kompatibel zu Datenzeigern und können nicht in die 
eine oder die andere Richtung konvertiert werden (auch wenn es die 
meisten C-Compiler trotzdem zulassen). Somit könnte ein Funktionszeiger 
völlig anders aufgebaut sein als ein Datenzeiger und auch auf einen 
eigenen Adressraum nutzen.

von Joachim B. (jar)


Lesenswert?

Axel S. schrieb:
> Aufpassen! Das ist eine Aussage über diese eine Implementierung mit
> dem Namen avr-gcc.

OK ist aber keine Antwort warum der m1284p trotz NICHTÜBERSCHREITEN der 
128KB langsamer zugreift als der m328p bei gleich großen 
überstreichendem Adressraum

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Schließlich weiß C nichts von Adressräumen.

Im Basis-Standard nicht, dafür aber in ISO/IEC TR 18037:
"C - Extensions to support embedded processors"
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1275.pdf

Beim AVR-GCC gibt es konform dazu 24-Bit Pointer, die Daten in sowohl 
ROM als auch RAM adressieren können. Ist natürlich zur Laufzeit etwas 
aufwändiger.
https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Named-Address-Spaces.html#Named-Address-Spaces

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Rolf M. schrieb:
> Axel S. schrieb:
>> Das ist nur ein Punkt, in dem ein Pointer mehr Information enthält als
>> eine Adresse. Ein anderer Punkt wäre der Adreßraum, in dem der Pointer
>> gilt. Schon avr-gcc kennt neben Pointern auf RAM auch Pointer auf Flash
>> und Pointer auf EEPROM. Auf anderen Architekturen mag es noch weitere
>> Adreßräume geben, durchaus auch mit sehr unterschiedlicher Größe. Es
>> gibt genau gar keinen Grund, warum der C-Compiler dann Pointer auf
>> unterschiedliche Adreßräume nicht auch mit unterschiedlicher Größe
>> codieren dürfte.
>
> Doch, den gibt es. Schließlich weiß C nichts von Adressräumen. Und ein
> int* hat eine statisch zur Compilezeit festgelegte Größe. Es gibt keine
> Zeiger auf "int in Adressraum X" oder sowsas.

Du haust hier zwei Dinge durcheinander. Das was du als C-Programmierer 
siehst und das, was der Compiler sieht. Bzw. sogar sehen muß. Schon 
avr-gcc muß für die Dereferenzierung eines char* unterschiedlichen Code 
generieren, je nachdem ob der auf einen String im RAM oder auf einen 
String im Flash zeigt. Rein durch einen Blick auf das C-Programm kann 
man jedenfalls nicht feststellen, ob der Compiler für
1
const char* msg="foobar";

einen Pointer in den Flash oder in das RAM anlegt.

> Der Compiler könnte also höchstens verschiedene Datentypen in getrennten
> Adressräumen unterbringen (also einer für short, einer für int u.s.w.).
> Das wäre aber eher ungewöhnlich.

Nimm noch Funktionszeiger dazu und schon ist es gar nicht mehr 
ungewöhnlich. Beim AVR liegt Code ausschließlich im Flash, Variablen 
hingegen ausschließlich im RAM.

> Und es muss dennoch möglich sein, jeden
> beliebigen Datenzeiger verlustlos in einen void* und zurück zu
> konvertieren, und diesen void* z.B. zu verwenden, um per memcpy die
> Daten umher zu kopieren.

Da ist kein Widerspruch. Ein void* muß einfach nur groß genug für jeden 
anderen Pointertyp sein. Wie die Konvertierung zwischen verschiedenen 
Pointertypen im Detail abläuft, kann Betriebsgeheimnis des Compilers 
bleiben. Die Pointertypen stehen zur Compilezeit fest.

von (prx) A. K. (prx)


Lesenswert?

Axel S. schrieb:
> Rein durch einen Blick auf das C-Programm kann
> man jedenfalls nicht feststellen, ob der Compiler für
>
> const char* msg="foobar";
>
> einen Pointer in den Flash oder in das RAM anlegt.

Bei ARM spielt es keine Rolle, aber bei AVR zeigt dieser Pointer in den 
Datenadressraum und der String liegt auch dort. Nur bei AVR-Versionen, 
die neben dem RAM noch anderen Speicher in den Datenadressraum mappen, 
kann dieser String ausserhalb des RAMs liegen.

Will man das anders haben, muss man es anders schreiben.

von Dr. Sommer (Gast)


Lesenswert?

Harry L. schrieb:
> * AVR-8bit ist Harvard-Architektur.
> * ARM ist von Neumann-Architektur

Die meisten (alle?) ARM-Prozessoren sind Harvard Architekturen, da sie 
(mindestens) 2 Busse für Daten und Instruktionen haben. Echte 
Von-Neumann-Architekturen gibt es kaum (gar nicht?) mehr. Moderne 
Prozessoren wie ARM und x86 kombinieren die Vorteile von Harvard und 
Neumann: Flexibilität des einheitlichen Adressraums, die Effizienz von 
Harvard dank 2 Bussen, und die Sicherheit von Harvard mittels MMU oder 
MPU (XN-Bits). Bei AVR muss der Compiler ggf die Neumannsche 
Flexibilität simulieren...

von Stefan F. (Gast)


Lesenswert?

Harry L. schrieb:
> AVR-8bit ist Harvard-Architektur.
> ARM ist von Neumann-Architektur

Bitte tut nicht so, als ob es nur diese beiden Architekturen gäbe. Es 
gibt viele weitere die der einen oder anderen oder gar beiden ähnlich 
sind.

Man sollte bedenken, dass die Technik seit etwa 100 Jahren schneller 
verändert wird, als die Schulbuchverlage und Lehrer mithalten können. 
Deswegen lehren sie oft noch uralte Sachen, die zwar nicht falsch aber 
unvollständig sind.

von (prx) A. K. (prx)


Lesenswert?

Dr. Sommer schrieb:
> Die meisten (alle?) ARM-Prozessoren sind Harvard Architekturen, da sie
> (mindestens) 2 Busse für Daten und Instruktionen haben.

Wie du selbst feststellst, ergibt der Begriff nur einen Sinn, wenn man 
ihn auf Adressräume bezieht, nicht auf Busse. Anno Harvard Mk I war das 
noch nicht ganz so kompliziert wie heute, da war das kein Unterschied.

Die ARM Cores bis einschliesslich der 7er haben keine getrennten Busse.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> OK ist aber keine Antwort warum der m1284p trotz NICHTÜBERSCHREITEN der
> 128KB langsamer zugreift als der m328p bei gleich großen
> überstreichendem Adressraum

Auf Function Pointer trifft das "so" nicht zu.
Denn der Compiler/Linker wird bei dem "kleinen" Flash keine tampolines 
nutzen.


Im Glaskugel Modus:
Davon ab, ist der m128p im Kern dem m2560 ähnlicher als dem m328p
Könnte mir vorstellen, dass die den Adressbus dort auch auf 22 Bit 
aufgeblasen haben, obwohl es faktisch nicht nötig wäre.
Es muss dann  bei jedem Funktionsaufruf 1 Byte mehr auf dem Stack 
gelagert werden, da der Rücksprung 24Bit breit gehändelt/gespeichert 
wird.

von Harry L. (mysth)


Lesenswert?

Dr. Sommer schrieb:
> Die meisten (alle?) ARM-Prozessoren sind Harvard Architekturen, da sie
> (mindestens) 2 Busse für Daten und Instruktionen haben. Echte
> Von-Neumann-Architekturen gibt es kaum (gar nicht?) mehr.

Blödsinn!
Das ist reinrassige von Neumann-Architektur.
Mit der Hardware-Umsetzung hat das gar nix zu tun.

Stefanus F. schrieb:
> Harry L. schrieb:
>> AVR-8bit ist Harvard-Architektur.
>> ARM ist von Neumann-Architektur
>
> Bitte tut nicht so, als ob es nur diese beiden Architekturen gäbe. Es
> gibt viele weitere die der einen oder anderen oder gar beiden ähnlich
> sind.

Du solltest dich erstmal informieren, bevor du sowas von dir gibts!

von (prx) A. K. (prx)


Lesenswert?

Arduino Fanboy D. schrieb:
> Könnte mir vorstellen, dass die den Adressbus dort auch auf 22 Bit
> aufgeblasen haben, obwohl es faktisch nicht nötig wäre.

Der ATmega128(P)(A) ist ziemlich alt und verwendet einen 16-Bit PC.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

A. K. schrieb:
> Die ARM Cores bis einschliesslich der 7er haben keine getrennten Busse.

Dann schau Dir mal das angehängte Bild an. Es stammt aus dem "Cortex-M3 
Technical Reference Manual" von ARM.
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0337h/DDI0337H_cortex_m3_r2p0_trm.pdf

Ich sehe da zahlreiche Busse, die teilweise über eine "Bus Matrix" 
miteinander verbunden sind. Die Taktfrequenzen der Busse sind nach 
meinem Kenntnisstand unterschiedlich einstellbar und wenn man 
Bus-Übergreifend (also durch die Matrix) auf sie zugreift entfallen 
unter Umständen Verzögerungen durch die Synchronisation der Takte an.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Auch im STM32F1 Reference Manual sind die Busse sehr deutlich getrennt 
gezeichnet. Siehe Anhang.

von (prx) A. K. (prx)


Lesenswert?

Stefanus F. schrieb:
>> Die ARM Cores bis einschliesslich der 7er haben keine getrennten Busse.
>
> Dann schau Dir mal das angehängte Bild an. Es stammt aus dem "Cortex-M3
> Technical Reference Manual" von ARM.

Wie hatten zwar gestern schon jemanden, der den Unterschied zwischen 7 
und 8  nicht recht verinnerlicht hatte, aber die ARM7* Cores haben mit 
den diversen Cortexen noch deutlich weniger gemein. Meine "7" bezog sich 
auf die frühere Nummerierung der Cores seitens ARM. Mit den ARM9 Cores 
trennten sich Befehle von Daten.

von Rolf M. (rmagnus)


Lesenswert?

Arduino Fanboy D. schrieb:
> Im Glaskugel Modus:
> Davon ab, ist der m128p im Kern dem m2560 ähnlicher als dem m328p
> Könnte mir vorstellen, dass die den Adressbus dort auch auf 22 Bit
> aufgeblasen haben, obwohl es faktisch nicht nötig wäre.
> Es muss dann  bei jedem Funktionsaufruf 1 Byte mehr auf dem Stack
> gelagert werden, da der Rücksprung 24Bit breit gehändelt/gespeichert
> wird.

Das Datenblatt scheint dazu etwas inkonsistent zu sein.
Einerseits steht in Kapitel 5.7.1:

"A return from an interrupt handling routine takes five clock cycles. 
During these five clock cycles, the Program Counter (three bytes) is 
popped back from the Stack, the Stack Pointer is incremented by three, 
and the I-bit in SREG is set."

Andererseits steht in Kapitel 6.2:

"The ATmega1284P Program Counter (PC) is 16 bits wide, thus addressing 
the 64K program memory locations."

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Auch im STM32F1 Reference Manual sind die Busse sehr deutlich getrennt
> gezeichnet. Siehe Anhang.

Was genau an

Harry L. schrieb:
> Mit der Hardware-Umsetzung hat das gar nix zu tun.

hast du nicht verstanden?

https://de.wikipedia.org/wiki/Harvard-Architektur
https://de.wikipedia.org/wiki/Von-Neumann-Architektur

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Stefanus F. schrieb:
> Auch im STM32F1 Reference Manual sind die Busse sehr deutlich getrennt
> gezeichnet. Siehe Anhang.

Die Cortexe implementieren zwar eine ARMv7-M Befehlssatz-Architektur, 
aber der ARM7TDMI implementierte ARMv4T. Die Cores nummerierten 
unabhängig von der Befehlssatz-Architektur, was man aber nur am dem "v" 
unterscheiden kann.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Das Datenblatt scheint dazu etwas inkonsistent zu sein.

Welches genau?

von Einer K. (Gast)


Lesenswert?

A. K. schrieb:
> Der ATmega128(P)(A) ist ziemlich alt und verwendet einen 16-Bit PC.



Arduino Fanboy D. schrieb:
> m128

Sorry, ich meinte den  m1284p

Es war eine Antwort auf:
Joachim B. schrieb:
> warum der m1284p

von Stefan F. (Gast)


Lesenswert?

Rolf M. schrieb:
> "The ATmega1284P Program Counter (PC) is 16 bits wide, thus addressing
> the 64K program memory locations."

Das ist auch richtig. Der Programmspeicher ist nämlich nicht 8bit Breit, 
sondern 16bit.

Im Gegensatz zum Datenspeicher kannst du den Programmspeicher des AVR 
nicht Byteweise adressieren.

von Joachim B. (jar)


Lesenswert?

Arduino Fanboy D. schrieb:
> Im Glaskugel Modus:
> Davon ab, ist der m128p im Kern dem m2560 ähnlicher als dem m328p
> Könnte mir vorstellen, dass die den Adressbus dort auch auf 22 Bit
> aufgeblasen haben, obwohl es faktisch nicht nötig wäre.
> Es muss dann  bei jedem Funktionsaufruf 1 Byte mehr auf dem Stack
> gelagert werden, da der Rücksprung 24Bit breit gehändelt/gespeichert
> wird.

das war meine Vermutung als ich vom 64K Adressraum ausging, deswegen 
verwirrt mich das ja so mit den 10% langsameren Zugriffen.

von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> deswegen
> verwirrt mich das ja so mit den 10% langsameren Zugriffen.

Du sprichst immer noch von Datenzugriffen, oder?
Wir sprechen über Funktion Pointer und Adressen auf dem Bus.

von Joachim B. (jar)


Lesenswert?

Arduino Fanboy D. schrieb:
> Du sprichst immer noch von Datenzugriffen, oder?
> Wir sprechen über Funktion Pointer und Adressen auf dem Bus.

https://www.mikrocontroller.net/attachment/244099/m1284p_timing.jpg

?
erkläre es du mir, das jedenfalls half
1
// Macro to convert from nano-seconds to clocks and clocks to nano-seconds
2
// __AVR_ATmega1284P__
3
// #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L)))
4
#if F_CPU < 96000000
5
    #if defined(__AVR_ATmega1284P__)
6
        #define NS(_NS) ( (_NS * ( ((long)(F_CPU*9L/10L)) / 1000000L))) / 1000
7
        #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (((long)(F_CPU*9L/10L)) / 1000000L)
8
    #else
9
        #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
10
        #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
11
    #endif
12
#else
13
    #define NS(_NS) ( (_NS * (F_CPU / 2000000L))) / 1000
14
    #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 2000000L)
15
#endif

von (prx) A. K. (prx)


Lesenswert?

Jetzt bräuchten wir nur noch den Code, auf den sich diese Rechnerei 
bezieht.

von Einer K. (Gast)


Lesenswert?

Joachim B. schrieb:
> erkläre es du mir, das jedenfalls half
Bahnhof!
Verstehe nicht, was du mir damit sagen/zeigen willst.

Du spricht über Datenzugriffe?
Die sind natürlich Byteweise adressierbar.
Darum wird man auf dem m1284p (über 64kByte Flash) mit 
pgm_read_byte_far() also mit den far Varianten arbeiten müssen.

Der Programmspeicher ist allerdings Word weise organisiert.
Darum braucht man die tampolines erst ab 128kByte Flash

von Rolf M. (rmagnus)


Lesenswert?

A. K. schrieb:
> Rolf M. schrieb:
>> Das Datenblatt scheint dazu etwas inkonsistent zu sein.
>
> Welches genau?

Das des ATmega1284P.
http://ww1.microchip.com/downloads/en/DeviceDoc/doc8059.pdf

Stefanus F. schrieb:
> Rolf M. schrieb:
>> "The ATmega1284P Program Counter (PC) is 16 bits wide, thus addressing
>> the 64K program memory locations."
>
> Das ist auch richtig.

Nein.

> Der Programmspeicher ist nämlich nicht 8bit Breit, sondern 16bit.

Es geht nicht um den Programmspeicher, sondern um den Program Counter, 
also das Register, das die aktuelle Position der Code-Ausführung 
enthält. An der einen Stelle steht, das sei 3 Bytes groß, an der anderen 
16 Bits.
Dass der Programmspeicher 16 Bit breit ist, steht nicht in Frage.

Arduino Fanboy D. schrieb:
> Joachim B. schrieb:
>> deswegen
>> verwirrt mich das ja so mit den 10% langsameren Zugriffen.
>
> Du sprichst immer noch von Datenzugriffen, oder?
> Wir sprechen über Funktion Pointer und Adressen auf dem Bus.

Bei Datenzugriffen sieht es natürlich ggf. auch nochmal anders aus. Denn 
dort braucht man ja eine Adresse auf Bytes, die für 128k Flash in 16 Bit 
nicht mehr reinpasst. Deshalb braucht man für Datenzugriffe auf den 
Flash mehr Bits. Dafür wird das Register RAMPZ verwendet.

von Stefan F. (Gast)


Lesenswert?

Rolf M. schrieb:
> Es geht nicht um den Programmspeicher, sondern um den Program Counter,
> also das Register, das die aktuelle Position der Code-Ausführung
> enthält. An der einen Stelle steht, das sei 3 Bytes groß

Steht so auch in meinem älteren Datenblatt von 2015. Komisch.

Der PC des ATmega1284 ist 2 bytes groß. Ganz sicher. Im Kapitel 
"In-System Reprogrammable Flash Program Memory" steht es an anderer 
Stelle klar drin:
1
The ATmega164A/164PA/324A/324PA/644A/644PA/1284/1284P Program Counter (PC) is 15/16 bits wide, thus addressing the 32/64K program memory locations.

von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Das des ATmega1284P.

In 7.5 fischt der RETI nur 2 vom Stack. Doku-Fehler - aber wo?

Beim ATmega128 tut er es auch in der Beschreibung vom Interrupt.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Dazu kommt, dass laut Datenblatt CALL und RET 5 Taktzyklen brauchen, was 
eigentlich nur gilt, wenn's 3 Byte sind.

von Joachim B. (jar)


Lesenswert?

A. K. schrieb:
> Jetzt bräuchten wir nur noch den Code, auf den sich diese Rechnerei
> bezieht.

arduino fastLED Lib
https://github.com/FastLED/FastLED

Rolf M. schrieb:
> Dazu kommt, dass laut Datenblatt CALL und RET 5 Taktzyklen brauchen, was
> eigentlich nur gilt, wenn's 3 Byte sind.

so sehe ich das auch, deswegen ist der Code auf dem m1284p ja langsamer

von (prx) A. K. (prx)


Lesenswert?

Joachim B. schrieb:
>> Jetzt bräuchten wir nur noch den Code, auf den sich diese Rechnerei
>> bezieht.
>
> arduino fastLED Lib
> https://github.com/FastLED/FastLED

Und wo dort?

von Joachim B. (jar)


Angehängte Dateien:

Lesenswert?

A. K. schrieb:
> Und wo dort?

ich habe eine ältere Version

in delay.h liegt meine Änderung, nach 1284 suchen

von (prx) A. K. (prx)


Lesenswert?

Joachim B. schrieb:
> A. K. schrieb:
>> Und wo dort?
>
> ich habe eine ältere Version
>
> in delay.h liegt meine Änderung, nach 1284 suchen

Da stehen irgendwelche Makros, die irgendwelche Zahlen umrechnen. 
Interessant ist aber der Code, in dem diese Makros genutzt werden.

von Carl D. (jcw2)


Lesenswert?

Harry L. schrieb:
> Stefanus F. schrieb:
>> Auch im STM32F1 Reference Manual sind die Busse sehr deutlich getrennt
>> gezeichnet. Siehe Anhang.
>
> Was genau an
>
> Harry L. schrieb:
>> Mit der Hardware-Umsetzung hat das gar nix zu tun.
>
> hast du nicht verstanden?
>
> https://de.wikipedia.org/wiki/Harvard-Architektur
> https://de.wikipedia.org/wiki/Von-Neumann-Architektur

Ich empfehle mal im "von Neumann"-Link etwas runterzublättern und die 
Abgrenzung zu "Harvard" durchzulesen. Nicht gemeinsamer oder getrennter 
Adressraum (aus Programmierersich) macht den Unterschied, sondern 
getrennte Busse für Befehls- und Datenzugriff (die dann überlappend 
passieren können).

In so fern bezeichnet die Firma ARM zurecht große Teile ihrer heutigen 
Produkte als "Harvard-Architektur".

von (prx) A. K. (prx)


Lesenswert?

Carl D. schrieb:
> Nicht gemeinsamer oder getrennter
> Adressraum (aus Programmierersich) macht den Unterschied, sondern
> getrennte Busse für Befehls- und Datenzugriff (die dann überlappend
> passieren können).

Es gibt beide Interpretationen, die orthodoxe und die sinnvolle.

Eine nützliche Aussage ergibt sich heute nur, wenn man sich dabei auf 
getrennte Adressräume bezieht. In der orthodoxen Interpretationen ist 
die Verwendung der Begriffe Harvard/Neumann heute sinnlos.

Andernfalls landet man bei ARM9 als Harvard und 8051 als von Neumann, 
weil der ARM9 getrennte Busse hat, während Intels 8051 zumindest im 
üblichen Blockbild nur einen Bus zeigt.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

A. K. schrieb:
> Es gibt beide Interpretationen, die orthodoxe und die sinnvolle.

Verstehe ich nicht.
1
Orthodoxie bezeichnet in der Grundbedeutung die Richtigkeit einer Lehrmeinung bzw. die Anhängerschaft der richtigen Lehrmeinung, im Gegensatz zu davon abweichenden Lehrmeinungen, die entsprechend für falsch erachtet und abgelehnt werden (Heterodoxie). Grundsätzlich betrachtet sich jede Lehrmeinung selbst als orthodox, so dass die Zuschreibung der Orthodoxie eine Frage des Standpunktes ist.
https://de.wikipedia.org/wiki/Orthodoxie

Demnach ist "deine" Interpretation gleichzeitig die sinnvolle und 
orthodoxe. Das ergibt so keinen Sinn.

von Rolf M. (rmagnus)


Lesenswert?

A. K. schrieb:
> Carl D. schrieb:
>> Nicht gemeinsamer oder getrennter
>> Adressraum (aus Programmierersich) macht den Unterschied, sondern
>> getrennte Busse für Befehls- und Datenzugriff (die dann überlappend
>> passieren können).
>
> Es gibt beide Interpretationen, die orthodoxe und die sinnvolle.
>
> Eine nützliche Aussage ergibt sich heute nur, wenn man sich dabei auf
> getrennte Adressräume bezieht.

Sehe ich nicht so. Für mich sind die hardwaremäßig getrennten 
Speicher-Busse für Daten und für Code das wesentliche Element. Der 
Vorteil von Harvard ist vor allem, dass dadurch ein Code- und ein 
Datenzugriff zeitgleich erfolgen kann.
Getrennte Adressräume hat man auch auf dem PC auch, sobald man 
virtuellen Speicher benutzt - nur sind diese bei gängigen 
Betriebssystemen immer auf den selben physischen Speicher gemappt. Ich 
würde den PC dennoch eher Richtung von-Neumann sehen als Richtung 
Harvard.
Generell ist eine harte Trennung aber kaum mehr möglich. Oft sind z.B. 
Caches für Code und Daten getrennt vorhanden, aber der Haupstspeicher 
nicht.

von Stefan F. (Gast)


Lesenswert?

Rolf M. schrieb:
> Generell ist eine harte Trennung aber kaum mehr möglich.

Danke, endlich sagt es auch mal jemand anderes.

von Harry L. (mysth)


Lesenswert?

Der Unteschied Harvard vs. von Neumann hat aber ganz konkrete 
Auswirkungen auf die Programmierung. (zumindest bei AVR 8bit)

Genau wegen dieser Harvard-Architektur bedarf es solcher Konstruktionen 
wie PROGMEM und pgm_read_xx().

Das ist bei von Neumann absolut nicht erforderlich, und die Anzahl der 
internen Busse ist vollkommen irrelevant.

Die werden dabei nämlich nur noch durch ihre Adressen in einem großen 
gemeinsamen Adressraum unterschieden.

Bei Harvard gibt es 2 logisch getrennte Adressräume.

von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Vorteil von Harvard ist vor allem, dass dadurch ein Code- und ein
> Datenzugriff zeitgleich erfolgen kann.

Solange man sich auf dem Level des Harvard Mk I bewegt, also in der 
ersten Vorlesungsstunde von Rechnerarchitektur, passt das. In der 
heutigen Realität passt das weder hinten noch vorne.

Ob diese Zugriffe gleichzeitig stattfinden oder nicht, interessiert 
heute lediglich ein paar Dutzend Leute in der Entwicklung von 
Prozessorchips. Der Rest der Welt interessiert sich für die erzielbare 
Leistung, und da ist das ein kleiner Aspekt von sehr vielen.

> Getrennte Adressräume hat man auch auf dem PC auch, sobald man
> virtuellen Speicher benutzt - nur sind diese bei gängigen
> Betriebssystemen immer auf den selben physischen Speicher gemappt.

Von Neumann kann man leidlich sauber als Klassifikation nutzen, indem 
man das auf einen gemeinsamen Adressraum von Code und Daten innerhalb 
eines Programms bezieht. In dem der Unterschied dazwischen nur in der 
Interpretation der Daten durch den Prozessor besteht, also Code auch vom 
Programm geschrieben werden kann (etwa durch einen Java JIT-Compiler). 
Das ist bei Trennung von Code und Daten unmöglich. In der orthodoxen 
Literatur rettet sich daraus über dem Begriff der modifizierten 
Harvard-Architektur. Auf getrennten Wegen an das gemeinsame Ziel 
gelangen.

Die Interpretation über getrennte Code/Datenräume enthält eine weiterhin 
nützliche Information, und zwar für den Programmierer. Die 
Interpretation über Busse enthält ausserhalb der Riege der Chipdesigner 
praktisch keine nützliche Information mehr.

Wobei das über Memory Mapping komplizierter werden kann, das stimmt. 
Einige PDP11 Versionen konnten mit 64kB I-Space und 64kB D-Space 
arbeiten. Mussten aber nicht. In diesem Sinn hat ein solcher Prozessor 
das Zeug zu beidem, je nachdem, wie der Prozess läuft. Der Maschine ist 
das folglich egal, aber nicht dem Programmierer. Für den ist dieser 
Unterschied von grosser Bedeutung.

> Generell ist eine harte Trennung aber kaum mehr möglich. Oft sind z.B.
> Caches für Code und Daten getrennt vorhanden, aber der Haupstspeicher
> nicht.

In den leistungsfähigeren Varianten gibt es den einen Speicherbus 
sowieso nicht mehr. Gruppen von Speichermodulen werden unabhängig über 
getrennte Wege angesprochen. Einerseits über 2-4 Speicherkanäle. Sind 
mehrere Prozessor-Dies vorhanden sind, hängt es überdies von der Adresse 
ab, ob der Speicher am eigenen Die hängt, oder an einem Kollegen, der 
vielleicht über Point-to-Point erreichbar ist, vielleicht über Crossbar. 
Und das geschieht so nicht nur zwischen Sockeln, sondern bei MCMs auch 
innerhalb davon (bei x86 z.B. AMD).

In physikalischer Sicht noch irgendwas über Busse zu klassifizieren, ist 
völlig sinnlos geworden. Es gibt davon zu viele.

von Stefan F. (Gast)


Lesenswert?

Harry L. schrieb:
> Genau wegen dieser Harvard-Architektur bedarf es solcher Konstruktionen
> wie PROGMEM und pgm_read_xx().

Moment mal. Die STM32F1 sind auch Harvard-Architektur. Aber bei denen 
brauchst du keine PROGMEM Konstrukte, weil es zwischen den Bussen noch 
eine Brücke gibt.

> Bei Harvard gibt es 2 logisch getrennte Adressräume.

Wie gesagt ist die Welt nicht so schwarz/weiss wie es manche gerne immer 
noch lehren würden.

Die Vorstellung, dass jeder Mikrocontroller entweder der Harvard oder 
der von Neumann Architektur entsprechen muss, ist obsolet. Gerade die 
STM32 und viele andere zeigen, dass beides gleichzeitig zutreffen kann.

Sicher gibt es auch Mikrocontroller die weder der einen noch der anderen 
Architektur entsprechen - also eine dritte Kategorie. Dieses Duale 
Schubladen-Denken beschränkt nur eure Kreativität unnötig.

Ihr würdet wahrscheinlich völlig verrückt werden, wenn ich euch eine CPU 
mit 13 Bit Registern, einer 17 Bit ALU und 29 Bit Programmzähler 
präsentieren würde. Mit einem gemeinsamen Datenbus für RAM und ROM, aber 
separaten Adressleitungen. Mit einer analogen Recheneinheit und einem 
sechseckigen Gehäuse aus Kartoffel-Stärke. Na wie wäre das? In welche 
Schublade würdet ihr diese CPU stecken?

von Harry L. (mysth)


Lesenswert?

...jetzt wundert es mich nicht mehr, daß man in mehr als 100 Beiträgen 
über das Verständnis von sowas Grundlegendem wie Pointer diskutieren 
kann....


Da bin ich direkt wieder raus...

von (prx) A. K. (prx)


Lesenswert?

Stefanus F. schrieb:
>> Es gibt beide Interpretationen, die orthodoxe und die sinnvolle.
>
> Verstehe ich nicht.

Ich verwendete "orthodox" im Sinn von "althergebracht", der alten Lehre 
folgend. Ich sehe diese nach wie vor oft vorgebrachte alte Lehre über 
die Busse schlicht als veraltet an.

von (prx) A. K. (prx)


Lesenswert?

Harry L. schrieb:
> ...jetzt wundert es mich nicht mehr, daß man in mehr als 100 Beiträgen
> über das Verständnis von sowas Grundlegendem wie Pointer diskutieren
> kann....

Wer sagt denn, dass grundlegende Dinge einfach sein müssen? Die Welt 
wird nicht nur im realen Leben immer komplizierter, sondern auch im 
virtuellen.

von mh (Gast)


Lesenswert?

In fast allen Fällen in denen etwas mit den Begriffen von-Neuman oder 
Harvard beschrieben wird, wird diese Beschreibung mehr Fragen auf als 
sie beantwortet. Vllt. sollte man gleich von Anfang an genau beschreiben 
was man meint.


Rolf M. schrieb:
> ... Für mich sind die hardwaremäßig getrennten
> Speicher-Busse für Daten und für Code das wesentliche Element. Der
> Vorteil von Harvard ist vor allem, dass dadurch ein Code- und ein
> Datenzugriff zeitgleich erfolgen kann.
> Getrennte Adressräume hat man auch auf dem PC auch, sobald man
> virtuellen Speicher benutzt - nur sind diese bei gängigen
> Betriebssystemen immer auf den selben physischen Speicher gemappt. Ich
> würde den PC dennoch eher Richtung von-Neumann sehen als Richtung
> Harvard. ...

Wo genau fängt denn der Speicher-Bus an, vor oder nach "dem" Cache? Wie 
werden Adressräume gewertet, die getrennt sind, aber nicht nach 
code/daten sondern z.B. nach code+schnelle daten/langsame daten? Was 
zählt als gleichzeitiger Zugriff im Zeitalter von SIMD, SIMT, OoO und 
speculative execution? Fragen über Fragen.

von Rolf M. (rmagnus)


Lesenswert?

Harry L. schrieb:
> Der Unteschied Harvard vs. von Neumann hat aber ganz konkrete
> Auswirkungen auf die Programmierung. (zumindest bei AVR 8bit)
>
> Genau wegen dieser Harvard-Architektur bedarf es solcher Konstruktionen
> wie PROGMEM und pgm_read_xx().

Das stimmt nicht so ganz. Das Problem ergibt sich eigentlich nur, weil 
der AVR eben keine reine Harvard-Architektur ist. Harvard heißt Trennung 
zwischen Code und Daten, und man liest keine Daten aus dem Codespeicher. 
AVR hat stattdessen eine Trennung zwischen RAM und Flash. PROGMEM und 
pgm_read_xx() brauche ich nur, wenn ich Daten aus dem Flash statt dem 
RAM lesen will.

A. K. schrieb:
> Ob diese Zugriffe gleichzeitig stattfinden oder nicht, interessiert
> heute lediglich ein paar Dutzend Leute in der Entwicklung von
> Prozessorchips. Der Rest der Welt interessiert sich für die erzielbare
> Leistung, und da ist das ein kleiner Aspekt von sehr vielen.

Harvard würde ich aber nicht über die Leistung, sondern eben über die 
Busse definieren.

>> Getrennte Adressräume hat man auch auf dem PC auch, sobald man
>> virtuellen Speicher benutzt - nur sind diese bei gängigen
>> Betriebssystemen immer auf den selben physischen Speicher gemappt.
>
> Von Neumann kann man leidlich sauber als Klassifikation nutzen, indem
> man das auf einen gemeinsamen Adressraum von Code und Daten innerhalb
> eines Programms bezieht. In dem der Unterschied dazwischen nur in der
> Interpretation der Daten durch den Prozessor besteht, also Code auch vom
> Programm geschrieben werden kann (etwa durch einen Java JIT-Compiler).
> Das ist bei Trennung von Code und Daten unmöglich.

Beim PC ist das ja eigentlich auch unmöglich und wird nur durch den 
Trick der Betriebssysteme erzielt, dass sie eben Code- und Datenspeicher 
auf den selben physischen Speicher mappen. Eigentlich sind es aber 
getrennte Adressräume, weil man für Code und Daten separate 
Segmentdeskriptoren braucht. Und Daten in ein für Codeausführung 
vorgesehenes Segment zu schreiben, ist nicht möglich.

>> Generell ist eine harte Trennung aber kaum mehr möglich. Oft sind z.B.
>> Caches für Code und Daten getrennt vorhanden, aber der Hauptspeicher
>> nicht.
>
> In den leistungsfähigeren Varianten gibt es den einen Speicherbus
> sowieso nicht mehr. Gruppen von Speichermodulen werden unabhängig über
> getrennte Wege angesprochen.

Das hat aber nichts damit zu tun, ob da Code oder Daten drin stehen. 
Harvard heißt ja nicht einfach nur, dass es mehr als einen Speicherbus 
gibt.

> In physikalischer Sicht noch irgendwas über Busse zu klassifizieren, ist
> völlig sinnlos geworden. Es gibt davon zu viele.

Das gilt für Adressräume genauso. Ich schrieb ja schon, dass bei 
modernen Prozessoren eine strenge Einteilung in Harvard und von Neumann 
recht sinnlos ist.

von A. S. (Gast)


Lesenswert?

Rolf M. schrieb:
> Und Daten in ein für Codeausführung
> vorgesehenes Segment zu schreiben, ist nicht möglich

Und wie kommt der Code dann da zur Laufzeit rein? Oder meinst Du 
geflashtes BIOS oder sowas?

von Einer K. (Gast)


Lesenswert?

Achim S. schrieb:
> Und wie kommt der Code dann da zur Laufzeit rein?
In dem man (das OS) einen Deskriptor erzeugt, welcher das Schreiben 
erlaubt.


Versehentliche Code Änderungen sollen unterbunden werden.
Prozesse/Tasks dürfen/können sich nicht gegenseitig stören.

von (prx) A. K. (prx)


Lesenswert?

Rolf M. schrieb:
> Beim PC ist das ja eigentlich auch unmöglich und wird nur durch den
> Trick der Betriebssysteme erzielt, dass sie eben Code- und Datenspeicher
> auf den selben physischen Speicher mappen. Eigentlich sind es aber
> getrennte Adressräume, weil man für Code und Daten separate
> Segmentdeskriptoren braucht. Und Daten in ein für Codeausführung
> vorgesehenes Segment zu schreiben, ist nicht möglich.

Wobei die Segmente mittlerweile weitgehend Makulatur sind. Code- wie 
Datensegment existieren nur noch pro forma und mappen nicht nur auf 
denselben physikalischen Speicher, sondern auch auf denselben virtuellen 
Speicher (linearer Speicher in Intel Nomenklatur). Ob ausführbar 
und/oder schreibbar ist daher eine Entscheidung auf der Ebene des 
Pagings, nicht der Segmentierung.

Einzig für thread local storage wird noch Segmentierung verwendet. Die 
kostet dann beim Zugriff 1 Takt extra.

: Bearbeitet durch User
Beitrag #5611185 wurde von einem Moderator gelöscht.
Beitrag #5611231 wurde von einem Moderator gelöscht.
Beitrag #5611268 wurde von einem Moderator gelöscht.
Beitrag #5611311 wurde von einem Moderator gelöscht.
von S. R. (svenska)


Lesenswert?

Rolf M. schrieb:
>> Es gibt genau gar keinen Grund, warum der C-Compiler
>> dann Pointer auf unterschiedliche Adreßräume nicht
>> auch mit unterschiedlicher Größe codieren dürfte.
>
> Doch, den gibt es. Schließlich weiß C nichts von Adressräumen.

Richtig, aber C kennt "Zeiger auf Dinge", und im Gegensatz zu C kennt 
der C-Compiler sowohl die Adressräume als auch die Dinge.

Und es steht ihm frei, die Zeiger beliebig zu definieren, solange er die 
restlichen Bedingungen nicht verletzt. Im Rahmen der Optimierung ist das 
auf manchen Architekturen sinnvoll.

> Und ein int* hat eine statisch zur Compilezeit festgelegte Größe.
> Es gibt keine Zeiger auf "int in Adressraum X" oder sowsas.

Als übliche Compiler-Erweiterung mit ganz aktuellen C (also sowas wie 
__flash) schon.

> Und es muss dennoch möglich sein, jeden beliebigen Datenzeiger
> verlustlos in einen void* und zurück zu konvertieren, und diesen
> void* z.B. zu verwenden, um per memcpy die Daten umher zu kopieren.

Richtig, ich muss nach void* und zurück wandeln können. Das heißt aber 
nicht, dass alle Zeiger unterschiedlich breit sind, sondern nur, dass 
ein void* alle Zeigertypen in sich aufnehmen kann.

Ein 24 Bit-Typ für "void*" und ein 16 Bit-Typ für alles andere wäre 
dementsprechend vollkommen ausreichend. :-)

von Einer K. (Gast)


Lesenswert?

S. R. schrieb:
> Ein 24 Bit-Typ
22 Bit ist ausreichend für alle AVR, auch für die mit dem X da dran.
Aber das passt nicht schön in 8 Bittige Bytes, und dann fängt wieder ein 
Geschrei an.

c-hater schrieb im Beitrag #5611185:
> unsäglichen dumm
Wer es sagt, der ist es auch!

Oder, wie die Kinder sagen: Spiegel!

von Carl D. (jcw2)


Lesenswert?

S. R. schrieb:
> Rolf M. schrieb:
>> Und ein int* hat eine statisch zur Compilezeit festgelegte Größe.
>> Es gibt keine Zeiger auf "int in Adressraum X" oder sowsas.
>
> Als übliche Compiler-Erweiterung mit ganz aktuellen C (also sowas wie
> __flash) schon.

Und in "N1275 draft of ISO/IEC DTR 18037" spezifiziert, d.h. keine 
GCC-Eigenheit, sondern mit Aussicht auf Aufnahme in den Standard.

von Rolf M. (rmagnus)


Lesenswert?

S. R. schrieb:
> Richtig, ich muss nach void* und zurück wandeln können. Das heißt aber
> nicht, dass alle Zeiger unterschiedlich breit sind, sondern nur, dass
> ein void* alle Zeigertypen in sich aufnehmen kann.
>
> Ein 24 Bit-Typ für "void*" und ein 16 Bit-Typ für alles andere wäre
> dementsprechend vollkommen ausreichend. :-)

Nicht ganz. Ein char* muss die gleiche Darstellung haben wie ein void*.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.