Sind Funktionspointer "spezielle" Pointer?

OP #4592275
Lesenswert?
• ▲
▼
Kernalhacker schrieb:
> Doch. Grundsätzlich schon. Die Zeiger können gleich sein, müssen es
> aber nicht (z.B. bei Harvard).
Wo wäre dann der Unterschied?

Peter II schrieb:
> bei C++ gibt es auch Funktionszeiger auf Memberfunktionen, die
> haben
> eine andere Größe, weil das Objekt und der Offset codiert werden müssen.
Ach... ich vergesse immer, dass der Filter nur die Ansicht ändert und 
nichts beim Posten: es geht um reines C.

Gruß
Dennis
#4592278
Lesenswert?
• ▲
▼
Dennis S. schrieb:
> gibt es einen Unterschied in der Implementierung (nicht Anwendung)
> von Zeigern auf Variablen und Zeigern auf Funktionen?

Auf einer von-Neumann-Machine nicht.

Auf einer Harvard Maschine schon, da können beide unterschiedliche 
Grössen haben

(z.B. Renesas M16: Datenpointer 16 bit, Funktionspointer 20 bit, uups, 
das ist eine von-Neumann-Maschine mit eingeschränktem Datenadressraum).

Ausnahmen gibt es also immer wieder, je nach kranker Architektir 
(Siemens C166 sach ich nur).

Ordentliche Prozessoren haben aber beide in der selben Grösse und können 
sie in denselben Registern und Speicherstellen aufbewahren, der 
Unterschied ergibt sich also bloss aus der Verwendung.
Moderator Persönliche Seite #4592283
Lesenswert?
• ▲
▼
Dennis S. schrieb:
> Wo wäre dann der Unterschied?

Bspw. in der Größe.  Wenn du zwei getrennte Busse für Daten und
Befehle hast, müssen diese ja nicht gleich groß sein.  Ein AVR mit
256 KiB Flash hat beispielsweise 17 Bit für Funktionszeiger (das
Bit 0 wird nicht gespeichert, weil Code immer auf geraden Adressen
liegt), aber nur 16 Bit für Datenzeiger.

Aus diesem Grunde schreibt der C-Standard auch vor, dass portabler
Code keine Zeiger zwischen Funktionen und Objekten hin und her
konvertieren darf.  Es ist allerdings garantiert, dass die Wandlung
eines Funktionszeigers in einen anderen Funktionszeigertyp und dann
zurück zum ursprünglichen funktioniert.
Gast #4592290
Lesenswert?
• ▲
▼
Michael B. schrieb:
> Auf einer von-Neumann-Machine nicht.

Gibt es überhaupt (noch) von-Neumann-Maschinen? Selbst die kleinsten 
MCU's haben doch zwei Datenbusse für Daten/Code, selbst wenn die in den 
selben Speicher gehen. Größere Prozessoren wie ARM oder gar x86 haben 
gern sogar noch mehr Busse (Speicher, Code, Peripherie, ...)

Es ist allerdings korrekt dass in C normale Zeiger und Funktionszeiger 
nicht gleich groß sein müssen. In C++ sind Member-Zeiger nochmal anders. 
Auf POSIX-Systemen wie Linux sind Funktions-und Datenzeiger aber immer 
gleich groß, denn sonst würden dlsym() und Konsorten nicht 
funktionieren.
#4592344
Lesenswert?
• ▲
▼
Dr. Sommer schrieb:
> Gibt es überhaupt (noch) von-Neumann-Maschinen?

Wenn man dem tieferen Sinn der Sache folgt und nicht bloss die Worte des 
Meisters runterbetet, dann wendet man diese Klassifizierung auf logische 
Adressräume statt physikalischer Datenbusse an. Solange man sich wie in 
dieser Frage auf der Ebene der Instruction Set Architecture befindet und 
nicht über Implementierungsdetails konkreten Siliziums diskutiert.
Gast #4592463
Lesenswert?
• ▲
▼
Schlimmer noch:
>> gibt es einen Unterschied in der
>> Implementierung von Zeigern?

Es gibt Systeme da sind nichtmal "Zeiger" auf RAM und auf (Flash)ROM 
gleich, auch wenn beides "Zeiger" auf Daten sind.
Es gibt Systeme die können gar keine "Zeiger" auf I/O.
Da haben wir gar noch nicht von "Zeiger" auf Code (Funktionen) 
gesprochen...

Zum Glück gibt es auf der anderen Seite auch Systeme bei denen alles 
orthogonal ist.

Ich hab Zeiger in Anf.strichen geschrieben weil es auf den Blickwinkel 
ankommt:
* physisch (von u.n.o.; Assembler) kommen die Unterschiede von 
separaten Bussysteme (RAM, ROM, I/O) welche nicht alle zwingend gleiche 
Breite in Bits haben und Maschineninstruktionen welche nicht alle Sorten 
(Daten, Code) verarbeiten können.
* logisch (von o.n.u.; Hochsprache) kommen die Unterschiede vom 
Verwendungszweck, der Absicht; also Äpfel (Zutaten) und Geschirr 
(Verarbeitung) gehören nun mal nicht mitenander verrechnet.


Klassischer Vergleiche:
- 80xx vs. 68xx (aus d. Scheibenwelt)
- x86 vs. SPARC (aus d. Planetensystem)
Moderator Persönliche Seite #4592464
Lesenswert?
• ▲
▼
Rolf M. schrieb:
>> Aus diesem Grunde schreibt der C-Standard auch vor, dass portabler
>> Code keine Zeiger zwischen Funktionen und Objekten hin und her
>> konvertieren darf.
>
> Eigentlich schreibt er sogar vor, dass man es gar nicht kann. Die Zeiger
> sind inkompatibel, und es müsste eine Fehlermeldung kommen.

Formal kannst du es als Zwischenschritt über eine Ganzzahl auffassen.
Wandlung eines Zeigers zu und von einer Ganzzahl ist zulässig (da
steht im Standard auch “any pointer type” und nicht “any object
pointer”), wobei das Verhalten dann implementierungsabhängig ist.
Undefiniert wird es nur, wenn der Wertebereich für die Ganzzahl durch
die Wandlung überschritten wird.

Damit ist natürlich zumindest abgedeckt, dass eine konkrete
Implementierung halt etwas wie das schon genannte dlopen() auch
implementieren darf.
#4592474
Lesenswert?
• ▲
▼
Jörg W. schrieb:
> Damit ist natürlich zumindest abgedeckt, dass eine konkrete
> Implementierung halt etwas wie das schon genannte dlopen() auch
> implementieren darf.

Aber wer castet schon den Rückgabewert erstmal in einen integer und dann 
in einen Funktionszeiger?
Der Compiler dürfte es eigentlich nicht zulassen, den Rückgabewert von 
dlsym() direkt in einen Funktionszeiger zu konvertieren, auch nicht mit 
einem Cast.
Moderator #4592636
Lesenswert?
• ▲
▼
Casts zwischen Objekt- und Funktonszeigern sind im C-Standard als
"common Extension" aufgeführt:

1
J.5 Common extensions
2

3
...
4

5
J.5.7 Function pointer casts
6

7
A pointer to an object or to void may be cast to a pointer to a
8
function, allowing data to be invoked as a function (6.5.4).
9

10
A pointer to a function may be cast to a pointer to an object or to
11
void, allowing a function to be inspected or modified (for example, by a
12
debugger) (6.5.4).

Ein explizites Verbot dieser Casts in unerweitertem C habe ich im
C-Standard nicht gefunden. Ich schätze, es ist bewusst weggelassen bzw.
aufgweicht worden, um einen Konflikt mit einem anderen Standard, nämlich
POSIX, zu vermeiden, der explizit die Möglichkeit dieser Casts fordert.
Gast #4592692
Lesenswert?
• ▲
▼
Uhu U. schrieb:
> Das hat aber nix mit der Implementierung des Pointers zu tun.

Indirekt schon, wenn die Adressen in verschiedenen Adressräumen sind, 
die unterschiedlich groß und ausgeprägt sein können (z.B. 
byte/wortadressierbarkeit, Segmentierung). Damit ändert sich dann das 
Bitformat des Zeigers.
#4592755
Lesenswert?
• ▲
▼
Yalu X. schrieb:
> Ein explizites Verbot dieser Casts in unerweitertem C habe ich im
> C-Standard nicht gefunden.

Hmm, ich dachte, es stünde irgendwo explizit, aber hab's jetzt auch 
nicht finden können. Es scheint also weder explizit verboten, noch 
explizit erlaubt zu sein.

Uhu U. schrieb:
> Peter D. schrieb:
>> Bei einer Funktion muß ein CALL ausgeführt werden, bei einer Variable
>> ein Lese oder Schreibzugriff (LD, ST).
>
> Das hat aber nix mit der Implementierung des Pointers zu tun.

Doch, schon. Eine Dereferenzierung macht ganz unterschiedliche Dinge.
#4592758
Lesenswert?
• ▲
▼
Rolf M. schrieb:
> Uhu U. schrieb:
>> Peter D. schrieb:
>>> Bei einer Funktion muß ein CALL ausgeführt werden, bei einer Variable
>>> ein Lese oder Schreibzugriff (LD, ST).
>>
>> Das hat aber nix mit der Implementierung des Pointers zu tun.
>
> Doch, schon. Eine Dereferenzierung macht ganz unterschiedliche Dinge.

Das sind Operationen auf Pointern, nicht der Pointer selbst.
#4592818
Lesenswert?
• ▲
▼
Uhu U. schrieb:
> Das sind Operationen auf Pointern, nicht der Pointer selbst.

Na wenn nicht so, dann gibt es gar keine Unterscheide, in C sind alle 
Ausdrücke nur Zahlen.
Ob Werte, Variablen oder Funktionen, alles wurscht.
Allein die Verwendung entscheidet, was aus der Zahl compiliert wird.
Z.B. hier mal die 0 als Funktionspointer:
1
  ((void(*)())0)();

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren