Forum: PC-Programmierung Ich dachte ich könnte C - was tut diese Zeile?


von Ruppelbutz (Gast)


Lesenswert?

Hallo,
bisher habe ich mich in C-Code immer ganz gut zurecht gefunden. Bis 
heute ;-)
Was zum Teufel macht das Komma und der hintere Teil da?

double const v = mReader->GetValue(offset), lastValue = mLastValue;

von Jonas K. (jonas_k)


Lesenswert?

1
int wert1 = 10, wert2 = 20;    // wert1=10 ,wert2=20

Zitat aus C von A bis Z, Kapitel 5.3
http://openbook.galileocomputing.de/c_von_a_bis_z/005_c_basisdatentypen_003.htm#mj68b293585c9b8a7d96028fa7e8b515a2

von cpp (Gast)


Lesenswert?

Ich würde sagen das ist C++ :-)
Es werdem die konstanten double Variablen v und lastValue deklariert und 
diese bekommen gleich Werte zugewiesen.
lastValue bekommt den Wert von mLastValue zugewiesen und v bekommt den 
Rückgabewert der Funktion GetValue(offset), die in einer hier nicht 
bekannten Klasse definiert ist bzw durch die Instanz mReader der Klasse 
instanziiert wurde.

von Ruppelbutz (Gast)


Lesenswert?

OK, jetzt raff ich's. Danke :-)

von Jonas K. (jonas_k)


Lesenswert?

cpp schrieb:
> Ich würde sagen das ist C++ :-)
> Es werdem die konstanten double Variablen v und lastValue deklariert und
> diese bekommen gleich Werte zugewiesen.
> lastValue bekommt den Wert von mLastValue zugewiesen und v bekommt den
> Rückgabewert der Funktion GetValue(offset), die in einer hier nicht
> bekannten Klasse definiert ist bzw durch die Instanz mReader der Klasse
> instanziiert wurde.

Ja, hast du recht. hab ich direkt überlesen, weils den Pfeiloperator ja 
in C auch gibt. Ist hier aber eindeutig C++ mit Klassen etc.

von Andreas (Gast)


Lesenswert?

>Ist hier aber eindeutig C++ mit Klassen etc.

Nein, wieso?
Kann das kann auch C sein.
Das kann man doch so gar nicht sagen.

von cpp (Gast)


Lesenswert?

Weil in C Klassen/Strukturen keine Funktionen enthalten können.

von Peter II (Gast)


Lesenswert?

cpp schrieb:
> Weil in C Klassen/Strukturen keine Funktionen enthalten können.

und wenn es ein funktionszeiger ist?

von Andreas (Gast)


Lesenswert?

Das ist C und würde funktionieren:
1
void Test()
2
{
3
  struct ReaderStruct
4
  {
5
    double (*GetValue)(int offset);
6
  } Reader;
7
8
  struct ReaderStruct *mReader;
9
10
  int offset = 0;
11
  double mLastValue = 0;
12
13
  double const v = mReader->GetValue(offset), lastValue = mLastValue;
14
15
16
}

Andreas

von cybmorg (Gast)


Lesenswert?

Ruppelbutz schrieb:
> bisher habe ich mich in C-Code immer ganz gut zurecht gefunden. Bis
> heute ;-)

C ist eine von den Sprachen, wo es eine Ehre sein kann, etwas nicht zu 
koennen... ganz einfach weil es ein Hinweis darauf ist, dass du im 
Praxisalltag gewisse Dinge, die in C zwar moeglich aber selten guter 
Stil sind, nicht tust. :-)

von Andreas (Gast)


Lesenswert?

>C ist eine von den Sprachen, wo es eine Ehre sein kann, etwas nicht zu
>koennen...

Das gilt aber ganz sicher  nicht für Pointer auf Funktionen!

Andreas

von Jonas K. (jonas_k)


Lesenswert?

Andreas schrieb:
> Das ist C und würde funktionieren:
>
>
1
void Test()
2
> {
3
>   struct ReaderStruct
4
>   {
5
>     double (*GetValue)(int offset);
6
>   } Reader;
7
> 
8
>   struct ReaderStruct *mReader;
9
> 
10
>   int offset = 0;
11
>   double mLastValue = 0;
12
> 
13
>   double const v = mReader->GetValue(offset), lastValue = mLastValue;
14
> 
15
> 
16
> }
17
>
>
> Andreas

Ich hätte gedacht, ein aufruf von Zeiger auf Funktionen müsste so 
ausschauen?
1
double (*GetValue)(int offset);
2
double const v = (*GetValue)(offset);
3
//kannte ich noch nicht:
4
double const v = GetValue(offset);

in der Struktur wäre das also beides möglich?
1
double const v = mReader->(*GetValue)(offset);
2
double const v = mReader->GetValue(offset);

von Yalu X. (yalu) (Moderator)


Lesenswert?

cybmorg schrieb:
> C ist eine von den Sprachen, wo es eine Ehre sein kann, etwas nicht zu
> koennen... ganz einfach weil es ein Hinweis darauf ist, dass du im
> Praxisalltag gewisse Dinge, die in C zwar moeglich aber selten guter
> Stil sind, nicht tust. :-)

Aber mehrere durch Komma getrennte Deklaratoren in einer Deklaration
sind doch kein schlechter Stil. Dasselbe gilt für Initialisierungen.

Die Sache mit dem Funktionszeiger scheint der TE ja noch verstanden zu
haben, erst ab dem Komma kamen die Probleme:

Ruppelbutz schrieb:
> Was zum Teufel macht das Komma und der hintere Teil da?

Wie auch immer, jetzt hat er's ja gerafft :-)

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jonas K. schrieb:
> Ich hätte gedacht, ein aufruf von Zeiger auf Funktionen müsste so
> ausschauen?

Man kann bei Funktionszeigern den Stern schreiben oder weglassen.
Dass der Zeiger dereferenziert wird (statt nur als Zeigerwert
weitergegeben), ergibt sich bereits eindeutig aus den anschließenden
runden Klammern.

von cybmorg (Gast)


Lesenswert?

Andreas schrieb:
> Das gilt aber ganz sicher  nicht für Pointer auf Funktionen!

Darauf habe ich mich auch nicht bezogen, sondern auf die urspruengliche 
Frage des Posters. Diese Art die Deklaration und Initialisierung von 
mehreren Variablen in eine Zeile zu quetschen, nur weil sie den gleichen 
Typ haben ist meist so ueberfluessig wie unleserlich.

von (prx) A. K. (prx)


Lesenswert?

Bei der ursprüngliche Sprachstruktur von C ist innerhalb von Ausdrücken 
der Name einer Funktion implizit ein Pointer auf diese Funktion. In
  void f(void);
  void (*p)(void);
sind sowohl "f" als auch "p" Pointer auf Funktionen. "f()" und "p()" 
sind folglich eine Dereferenzierung dieser Pointer.

Dass man neben "... = f;" und "p()" auch "... = &f;" und "(*p)()" 
schreiben kann ist strukturell unlogisch. Es ist eine Konzession an 
jene, die das ursprüngliche Konzept verwirrt hat.

von cybmorg (Gast)


Lesenswert?

Yalu X. schrieb:
> Aber mehrere durch Komma getrennte Deklaratoren in einer Deklaration
> sind doch kein schlechter Stil. Dasselbe gilt für Initialisierungen.

Was ist denn der Vorteil davon? Dass ein paar Zeilen gespart werden? Und 
dafuer stehen Variablendeklarationen, deren einzige gemeinsame Beziehung 
der gleiche Typ ist auf einer Zeile?

Aber die Diskussion ist sinnlos - fuer viele alte C-Hacker geht 
Kompaktheit immer vor Lesbarkeit. Es ist eine Frage von wenigen Posts, 
bis die ersten elitaeren Sprueche kommen...

von (prx) A. K. (prx)


Lesenswert?

Der Komma-Operator in Ausdrücken ist/war im Zusammenhang mit 
Präprozessor-Macros notwendig. Als es noch keine Inline-Funktionen gab, 
war etwas wie getc() anders nicht effizient implementierbar.

Im Statement des TO ist der freilich nicht wirklich angebracht.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Im Statement des TO ist der freilich nicht wirklich angebracht.

Naja, dort ist es aber kein Komma-Operator, sondern das
Aufzählungskomma in einer Variablendefinition. =:-)

Ansonsten bekäme "v" ja den Wert von "lastValue", nicht den, den
mReader->GetValue() zurückgibt.  Beim Kommaoperator ist schließlich
der Teilausdruck links des Kommas nur zu bewerten, trägt aber nicht
zum Resultat bei.

von (prx) A. K. (prx)


Lesenswert?

Jörg Wunsch schrieb:
> Naja, dort ist es aber kein Komma-Operator, sondern das
> Aufzählungskomma in einer Variablendefinition. =:-)

Hehe, stimmt.

Wobei das Komma in Definitionen sich in for-Statements gelegentlich 
nützlich macht. Seit die dort zulässig sind.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

A. K. schrieb:
> In
>   void f(void);
>   void (*p)(void);
> sind sowohl "f" als auch "p" Pointer auf Funktionen.

Vorsicht: Ähnlich, wie ein Array nicht das Gleiche wie ein Pointer auf
sein erstes Element ist, ist auch eine Funktion nicht das Gleiche wie
ein Pointer auf diese Funktion.

Der Unterschied wird klar, wenn man nach der Zuweisung p = f den
&-Operator auf f und p anwendet. Sowohl der Typ als auch der numerische
Inhalt von &f und &p sind verschieden.

Dafür ist aber f das Gleiche wie *****f und *******p (Anzahl der * ist
beliebig), was bei Arrays in entsprechender Weise nicht gilt.

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> Der Unterschied wird klar, wenn man nach der Zuweisung p = f den
> &-Operator auf f und p anwendet.

Das liegt an der erwähnten Inkonsequenz durch 2 verschiedene 
gleichzeitig zulässige jeweils nur in sich konsistenter Schemata:
(1)   p = f; p(); f();
(2)   p = &f; (*p)(); f();

Innerhalb von (1) ist in Ausdrücken
  f
ein Pointer, also die Adresse der Funktion,
  f()
die Dereferenzierung eines Pointers und
  &f;
ist undefiniert, weil das vergleichbar ist zu
  &1;

Innerhalb von (2) ist in Ausdrücken
  f
eine Funktion, nicht deren Adresse,
  f()
keine Dereferenzierung, und
  f;
  p = f;
ist undefiniert, liesse sich aber als Aufruf ohne Parameter verstehen, 
wie in anderen Sprachen realisiert.

Da kein Konflikt zwischen (1) und (2) entsteht konnte man beides 
gleichermassen zulassen. Aber dadurch gibts eben ein paar merkwürdige 
Effekte, wenn man anfängt, drüber nachzudenken, und wenn man beide 
Schemata mischt.

Ich gehe davon aus, dass es zunächst nur (1) gab und (2) später hinzu 
kam, weil manchen (1) nicht verständlich war.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

A. K. schrieb:
> Das liegt an der erwähnten Inkonsequenz durch 2 verschiedene
> gleichzeitig zulässige jeweils nur in sich konsistenter Schemata:

Diese Inkonsistenz verschwindet, wenn man statt der beiden von dir
vorgeschlagenen Schemata folgende drei Auswerteregeln anwendet, die
denen für Arrays ähnlich sind und die im Wesentlichen den neueren
C-Standards entsprechen:

1. Ein Ausdruck, der eine Funktion liefert, wird durch einen Pointer auf
   diese Funktion ersetzt, es sei denn, der Ausdruck ist Argument des
   sizeof- oder des Adressoperators. In diesem Fall bleibt der Ausdruck
   unverändert.

2. Der sizeof-Operator auf eine Funktion angewendet ist ein Fehler¹.

3. Ein Funktionspointer mit nachfolgender eingeklammerter Argumentliste
   bewirkt einen Aufruf der Funktion, auf die der Pointer zeigt.

Damit sind alle diese Fälle in konsistenter Weise abgedeckt:

> (1)   p = f; p(); f();
> (2)   p = &f; (*p)(); f();


> Ich gehe davon aus, dass es zunächst nur (1) gab und (2) später hinzu
> kam, weil manchen (1) nicht verständlich war.

Wenn man im "C Reference Manual" von Dennis Ritchie die entsprechenden
Informationen zusammenträgt, sind folgende Anweisungen
1
  f();     /* klar */
2
  p = f;   /* "function returning ..." wird in "pointer to function returning ..." konvertiert */
3
  (*p)();  /* (*p) liefert "function returning ..." */

in Ordnung, nicht aber diese:
1
  p = &f;  /* der Adressoperator war damals nur für lvalues zugelassen, f ist aber keiner */
2
  p();     /* p ist nicht vom Typ "function returning ..." */

Es passt also keines der beiden von dir genannten Schemata.


———————————
¹) Der GCC erweitert die Definition von sizeof dahingehend, dass sie bei
   der Anwendung auf eine Funktion den Wert 1 liefert.

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> Damit sind alle diese Fälle in konsistenter Weise abgedeckt:

Konsistent geht für mich anders, wenn &f gerne mal das gleiche ist wie 
f, und *p das gleiche wie p. Ich sehe das eher als Regelsatz für "naja 
ok, es funktioniert so irgendwie". ;-)

> Wenn man im "C Reference Manual" von Dennis Ritchie die entsprechenden
> Informationen zusammenträgt, sind folgende Anweisungen

Stimmt. Leider. Ok, viel Sinn für innere Logik konnte man Ritchie 
ohnehin nicht vorwerfen.

Wirth über C: "It is indeed absolutely surprising with which eqanimity 
this notational monster was accepted by the world-wide programmer’s 
community."

: Bearbeitet durch User
von Bastler (Gast)


Lesenswert?

Wobei der liebe Nikolaus natürlich ganz objektiv über seine Mitbewerber 
geurteilt hat ;-)

von (prx) A. K. (prx)


Lesenswert?

Bastler schrieb:
> Wobei der liebe Nikolaus natürlich ganz objektiv über seine Mitbewerber
> geurteilt hat ;-)

Angesichts dessen, dass der Dicke mit "o" immer noch überall rumspringt, 
und farblich grosse Ähnlichkeit mit der Schweizer Fahne aufweist, sei 
dir die Verwechselung verziehen. ;-)

Der ist anders gewickelt. Prof eben, mit Sinn für sprachliche Ästhetik, 
kein Wirtschaftler. C++ hat das ganze dann quadriert, da hatten sich mir 
nach Lektüre von Stroustrups Werk stellenweise die Zehennägel 
gekräuselt.

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


Lesenswert?

A. K. schrieb:
> Prof eben, mit Sinn für sprachliche Ästhetik,
> kein Wirtschaftler.

Nur hat er in seinem Konstrukt "Pascal" Dinge drin, die mit Pascal 
selbst nicht erzeugt werden können -- variadische Funktionen nämlich.

Eine Funktion wie write oder writeln kann man in Pascal selbst nicht 
schreiben.

von Paul B. (paul_baumann)


Lesenswert?

Wer readln will, muß vorher auch writeln wollen!
;-)
MfG Paul

von (prx) A. K. (prx)


Lesenswert?

Deshalb sah das in späteren Werken ja auch anders aus. Wenn man Sprachen 
schafft, die nicht so einschlagen wie C, hat man gewisse Freiheiten, es 
das nächste Mal besser zu machen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

A. K. schrieb:
> Wenn man Sprachen schafft, die nicht so einschlagen wie C, hat man
> gewisse Freiheiten, es das nächste Mal besser zu machen.

So ist es.

Irgendjemand (vielleicht war es sogar jemand hier im Forum) hat einen
Spruch ähnlich dem folgenden geprägt:
1
  Es gibt zwei Sorten von Programmiersprachen:
2
  Solche, die unsauber sind, und solche, die keiner benutzt.

von Jean P. (fubu1000)


Lesenswert?

A. K. schrieb:

> Wirth über C: "It is indeed absolutely surprising with which eqanimity
> this notational monster was accepted by the world-wide programmer’s
> community."

Tja, in jeder Sprache gibt es Ungereimtheiten.
Im Englischen gibt es "the",
im Deutschen "der, die , das".
Wo ist das Problem ? Lerne die Sprache, benutze Sie und vergewaltige Sie 
nicht, wie 'Ihr da oben tut.

Just my cent
P.S: was ist denn die tolle Sprache ohne Fehler ?

von Hans (Gast)


Lesenswert?

Yalu X. schrieb:
> A. K. schrieb:
>> Wenn man Sprachen schafft, die nicht so einschlagen wie C, hat man
>> gewisse Freiheiten, es das nächste Mal besser zu machen.
>
> So ist es.
>
> Irgendjemand (vielleicht war es sogar jemand hier im Forum) hat einen
> Spruch ähnlich dem folgenden geprägt:
>   Es gibt zwei Sorten von Programmiersprachen:
>   Solche, die unsauber sind, und solche, die keiner benutzt.

Das stammt von Stroustrup (Erfinder von C++).
1
There are only two kinds of programming languages:
2
Those people always bitch about and those nobody uses.

:)

von Peter (Gast)


Lesenswert?

Hallo zusammen,

Ich lese den Thread, da ich gerade auch weiter in die Programmierung in 
C ensteigen möchte. Daher bleibt einem der Umgang mit Pointern natürlich 
nicht erspart. Gerade bei Ringpuffern möchte ich ohne Pointer gar nicht 
mehr auskommen.
Das man einem Pointer eine Funktion zuweist ist mehr noch recht neu und 
daher stelle ich mal ganz dumm die Frage: Welchen grossen Vorteil hat 
man da? Zuerst habe ich ja mal mehr "arbeit". Ich muss einen Pointer 
anlegen, ihm die Funktion bzw Adresse der Funktion zuweisen und erst 
dann kann ich die Funktion aufrufen. Also ich sehe darin gerade keinen 
Vorteil aber es gibt ihn oder vielleicht sogar mehrere.

von Andreas (Gast)


Lesenswert?

>Also ich sehe darin gerade keinen
>Vorteil aber es gibt ihn oder vielleicht sogar mehrere.

Es gibt mehrere Vorteile:
Man kann die Pointer in Arrays oder Hashtables packen und
einfach über den Index bzw. Key die Funktionen aufrufen
ohne lange if oder switch Anweisungen schreiben zu müssen.

Die Funktions Pointer in Arrays und Hashtables kann man
natürlich auch zur der Laufzeit ändern.

Beim Laden von DLLs zur Laufzeit benötigt man Funktions Pointer
umd die Funktionen in der DLL aufzurufen.

Andreas.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hans schrieb:
> Das stammt von Stroustrup (Erfinder von C++).
>
> There are only two kinds of programming languages:
> Those people always bitch about and those nobody uses.
> :)

Klasse! Genau danach hatte ich gesucht, aber nichts gefunden, weil ich
mich weder an den genauen Wortlaut noch an den Autor, ja, nicht einmal
an die Sprache (Englisch/Deutsch) erinnerte.


@Peter:

Eine weitere Anwendung für Funktionszeiger:

  http://de.wikipedia.org/wiki/Callback-Funktion

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.