temp. Referenz auf typecast als Fkt.argument

Post Reply
Message
Author
C-Lerner

temp. Referenz auf typecast als Fkt.argument

#1 Post by C-Lerner »

Hallo,
eine (Un)Tugend von C-Programmierern ist Schreibfaulheit, da wollte ich über Ostern noch ein wenig lernen ...
Ich habe ein double, eine Funktion möchte aber einen Pointer auf einen integer, kann das casten und pointern in einem Rutsch (als intelligente Zuarbeit des Compilers) erledigt werden, oder geht es wirklich nur mit einer explizieten integer-Hilfsvariablen?

Code: Select all

double dbl = 1234.56;
int itemp;

/* ueber Umweg o.k. */
itemp = (int)dbl;
fkt_moechte_pint( &itemp );

/* logisch falsch, aber alle anderen Versuche, erst int, dann &,
    werden vom Compiler bemeckert: */
fkt_moechte_pint( (int*)&dbl );
Danke für hilfreiche Hinweise oder auch nur moralische Unterstützung,
frohe Ostern!

Der ewig Lernende

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#2 Post by Janka »

Du musst explizites und implizites Typecasting unterscheiden:

Implizites Typecasting funktioniert, indem die Ergebnisseite einer Evaluation einen bestimmten Typ hat. Bei deinem Beispiel mit der Funktion ist dieser Typ ein pointer. D.h. du könntest hier implizit den Wert eines Pointers casten lassen (bspw. near->far-Pointer), aber nicht den Wert des vom Pointer anvisierten Objekts.

Explizites Typecasting kann man immer nur auf einen im Laufe der Evaluation eines Ausdrucks auftretenden Wert anwenden. Wenn eine Funktion einen pointer verlangt, kannst du also einen anderen Pointertyp darauf casten. Du kannst aber nicht den Wert des anvisierten Objektes casten, denn dieser Wert taucht ja beim Berechnen des pointers auf dieses Objekt gar nicht auf!

Janka

C-Lerner

#3 Post by C-Lerner »

Ja, so wie Du es schreibst, mit den "auftretenden Werten" ist es zu erklären. Ich nehme an, bei C++ wird es wohl auch nicht anders sein.

Danke.

Trotzdem denke ich, dass der Wert (also das Ergebnis) von int(dbl) bei der Evalution auftritt (und nicht im digitalem Nirvana verschwindet) und somit statt der Pünktchen auch weiteres explizietes Typecasting stehen könnte.

fkt_moechte_pint( ...(int)dbl )

Aber allein die Schreibweise der Typwandlung lässt vermuten, dass es sich hier um ein recht komisches Stück C handelt.

So wäre es für mich logisch:

fkt_moechte_pint( &(int(dbl)) );

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#4 Post by Janka »

C-Lerner wrote: Trotzdem denke ich, dass der Wert (also das Ergebnis) von int(dbl) bei der Evalution auftritt (und nicht im digitalem Nirvana verschwindet) und somit statt der Pünktchen auch weiteres explizietes Typecasting stehen könnte.

fkt_moechte_pint( ...(int)dbl )

Aber allein die Schreibweise der Typwandlung lässt vermuten, dass es sich hier um ein recht komisches Stück C handelt.
Das ist eine vollkommen korrekte Typwandlung, wenn an dieser Stelle der Funktionsargumente ein int erwartet wird.
So wäre es für mich logisch:
fkt_moechte_pint( &(int(dbl)) );
Und genau hier liegt dein Verständnisproblem: Du möchtest den C-Compiler hier anweisen, den Wert an einer Speicherstelle, an der bisher ein double-Wert stand, *dort* in einen int-Wert zu verwandeln. Danach soll die Adresse der Speicherstelle als pointer in die Funktion hineingestopft werden.

So eine Operation ist jedoch *keine* Typwandlung mehr, da das Orginal *dbl dabei zerstört werden würde. Daher ist dieser Fall in einem C-Compiler auch nicht vorgesehen.

Immer beachten: Deine Funktion möchte einen pointer zu fressen haben - Typwandlungen beziehen sich also hier immer auf *pointer*, nicht auf das was sie zeigen. Scheint schwer einzusehen zu sein, ist aber so.

Janka

C-Lerner

#5 Post by C-Lerner »

Und genau hier liegt dein Verständnisproblem: Du möchtest den C-Compiler hier anweisen, den Wert an einer Speicherstelle, an der bisher ein double-Wert stand, *dort* in einen int-Wert zu verwandeln. Danach soll die Adresse der Speicherstelle als pointer in die Funktion hineingestopft werden.
Gefehlt. Wie kommst Du auf *dort* ?
Bei

fkt_moechte_pint( &(int(dbl)) );

würde der Wert der Variable dbl auf den Parameterstack der Funktion int (floor wäre ja überflüssig) gepackt, der Rückgabewert von int darf dann ebenfals auf den Stack und genau diese Adresse darf der Compiler dann an fkt_moechte_pint weiterreichen. Ist das von einem Compiler zu viel verlangt, x = a + b * c schafft er doch auch.
(Selbst wenn es int(&dbl) hieße, bedeutet es dann nicht, dass dbl verändert würde.)
Es ist eben die Abartigkeit von C, Typumwandlungen nicht als Funktion zu sehen. Warum, konnte mir noch niemand erklären.

Der ewig Lernende

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#6 Post by Janka »

C-Lerner wrote: Gefehlt. Wie kommst Du auf *dort* ?
Bei

fkt_moechte_pint( &(int(dbl)) );

würde der Wert der Variable dbl auf den Parameterstack der Funktion int (floor wäre ja überflüssig) gepackt, der Rückgabewert von int darf dann ebenfals auf den Stack und genau diese Adresse darf der Compiler dann an fkt_moechte_pint weiterreichen.
Der Compiler soll deiner Meinung nach also Annahmen darüber machen, was die Funktion mit der Adresse tun möchte. Vielleicht möchte die Funktion ja Pointerarithmetik machen, oder erwartet ein Array (das ja auch als Pointer übergeben wird). Dann muss der Compiler *sehr viel mehr* über die Funktion wissen als ihren Prototyp. So oder so, das ist mehr als eine simple Typwandlung.
Ist das von einem Compiler zu viel verlangt, x = a + b * c schafft er doch auch.
(Selbst wenn es int(&dbl) hieße, bedeutet es dann nicht, dass dbl verändert würde.)
Es ist eben die Abartigkeit von C, Typumwandlungen nicht als Funktion zu sehen. Warum, konnte mir noch niemand erklären.
Weil Typumwandlungen, die die binäre Repräsentation eines Wertes ändern, kein so wesentliches Feature von C sind. In C ist es nur eine Bequemlichkeit, dass der Compiler automatisch Code erzeugt, der floats, ints etc. gemischt in Ausdrücken erlaubt. Die Bequemlichkeit hört aber sofort auf, sobald mehr als der aktuelle Ausdruck im Spiel ist, und das ist beim Umgang mit gepointerten Werten halt schnell der Fall.

Wenn du sowas haben willst, musst du C++ nehmen, oder besser gleich Java. C ist gebastelt worden, um systemnahe Programme nicht in Assembler basteln zu müssen. Alle Semantiken von C sind im Prinzip Semantiken von Assembler. Wenn du C meistern willst musst du dich damit anfreunden.

Dazu eine berühmte Zeile: "The C Programming Language -- A language which combines the flexibility of assembly language with the power of assembly language."

Janka

C-Lerner

#7 Post by C-Lerner »

Der Compiler soll deiner Meinung nach also Annahmen darüber machen, was die Funktion mit der Adresse tun möchte. Vielleicht möchte die Funktion ja Pointerarithmetik machen, oder erwartet ein Array (das ja auch als Pointer übergeben wird). Dann muss der Compiler *sehr viel mehr* über die Funktion wissen als ihren Prototyp. So oder so, das ist mehr als eine simple Typwandlung.
Nein.
Bitte keine falschen Annahmen! Es ist auch völlig egal, ob die Funktion mit ihrem Argument Pointerarithmetik oder Hüftumschwünge macht.
fkt_moechte_pint( &(int(dbl)) );
ist doch wohl eindeutig genug, auch wenn ich mich wiederhole:
Ganzzahl von einer Kommazahl bilden, die Adresse dieses Ergebnisses als Argument beim Aufruf von fkt_moechte_pint verwenden.
Die Typwandlung in C ist halt nicht nur syntaktischer Käse.
Schriebe ich mir statt & eine Funktion (int*)addr( int i ), wäre es doch dann so o.k.:
fkt_moechte_pint( addr( floor( dbl ) ) );
Nur halt weniger effizient (zur Laufzeit).
C wurde gebastelt -- das ist wohl die korrekte Beschreibung.

Ich danke nochmals für die Aufklärung,
der ewig Lernende

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#8 Post by Janka »

C-Lerner wrote: Es ist auch völlig egal, ob die Funktion mit ihrem Argument Pointerarithmetik oder Hüftumschwünge macht.
fkt_moechte_pint( &(int(dbl)) );
ist doch wohl eindeutig genug, auch wenn ich mich wiederhole:
Ganzzahl von einer Kommazahl bilden, die Adresse dieses Ergebnisses als Argument beim Aufruf von fkt_moechte_pint verwenden.
Die Typwandlung in C ist halt nicht nur syntaktischer Käse.
Schriebe ich mir statt & eine Funktion (int*)addr( int i ), wäre es doch dann so o.k.:
fkt_moechte_pint( addr( floor( dbl ) ) );
Nur halt weniger effizient (zur Laufzeit).
Du bastelst hier ein Gedankenkonstrukt, das für *deinen einen Fall* funktioniert. Was ist mit den anderen Fällen, in denen es der Funktion nicht egal ist, ob der Zeiger auf einen einzelnen int auf dem Stack zeigt, oder auf ein int-Array irgendwo in den weiten des Speichers? C legt sich hier nicht fest, und deswegen wird der Compiler solche Typumwandlungen auch nicht vornehmen.

Wie ich oben schrieb: Dann muss der Compiler *sehr viel mehr* über die Funktion wissen als ihren Prototyp

Janka

Post Reply