Probier es doch einfach mal aus.
Antwort: Nein. NULL ist kein Objdata_t. Du kannst aber auch einen Zeiger
auf Objdata_t zurückgeben...
Und dein return obj; "funktioniert" zwar insofern, als der Compiler es
übersetzt, es macht aber nicht das, was du sillst und ist ein grober
Schnitzer.
Und man sieht dort sehr schön einen großen Vorteil von Rust
(www.rust-lang.org): Der läßt das return obj; nämlich nicht zu, weil er
die Lebensdauer von Variablen überprüft (und aufgrund des
Rust-Typsystems im gegensatz zu C/C++ das auch eindeutig überprüfen
kann).
Fred schrieb:> Und dein return obj; "funktioniert" zwar insofern, als der Compiler es> übersetzt, es macht aber nicht das, was du sillst und ist ein grober> Schnitzer.
warum denn nicht? Es wird dabei eine Kopie vom objekt erzeugt und diese
zurückgegeben.
Es wird allgemein angenommen das ein objekt selber nicht NULL sein
sollte. Auch wenn es technisch geht.
wenn du also ein objekt oder NULL zurückgeben willst. dann verwende ein
zeiger.
Walter Tarpan schrieb:> Hallo zusammen,> ich frage mich gerade, wie unter C das Nullelement eines struct> aussieht.
Was meinst du mit "das Nullelement eines Struct"? Ein struct besteht aus
mehreren Variablen, von denen jedes je nach Typ 0 sein kann oder auch
nicht.
> Ich habe eine Funktion, die in etwa so aufgebaut ist:> typedef struct{ ... } Objdata_t;>> Objdata_t Objinit(Objinittype_t Init)> {> Objdata_t obj;>> [...]>> return obj;>> error:> return NULL; // geht das?
Nein. NULL ist für Zeiger vorgesehen, um anzugeben, daß ein Zeiger keine
gültige Objekt-Adresse enthält. Ein Struct enthält aber keine Adresse.
> }>> und ich würde in der aufrufenden Funktion gern prüfen, ob die> Initialisierung fehlgeschlagen ist, etwa so[...]> Objdat = Objinit(Init);> if(Objdat==NULL) goto error;> [...]>> Geht das so? Laut C-Standard kann man structs ja nicht vergleichen.
Wenn du deine Objekte irgendwie als "ungültig" markieren und später
erkennen können willst, mußt du dir selber eine Methode dafür überlegen.
Fred schrieb:> Und dein return obj; "funktioniert" zwar insofern, als der Compiler es> übersetzt, es macht aber nicht das, was du sillst und ist ein grober> Schnitzer.
Nein. Es ist nicht sonderlich performant, aber es funktioniert im Sinne
des Erfinders.
C kennt seit C89 Strukturzuweisungen, und damit kann eine Struktur auch
als Rückgabewert einer Funktion verwendet werden.
Ineffizient ist es, weil bei einer Strukturzuweisung die komplette
Struktur kopiert wird; hier wird sie gleich zweimal kopiert, einerseits
bei der Übergabe via return (da wird die lokale Struktur auf den Stack
kopiert (auch wenn sie als automatische Variable eh' schon auf dem Stack
lieg) und andererseits bei der Zuweisung an "Objdat" als Rückgabewert
der Funktion (da wird sie vom Stack wiederum in Objdat kopiert).
Wobei das als Zeiger so aber auch nicht funktionieren würde, weil der
Zeiger auf eine lokale Variable zeigt, die auf dem Stack liegt und bei
Verlassen der Funktion nicht mehr gültig ist.
Dann sollte man den Zeiger auf die (ausserhalb definierte) Struktur
besser als Parameter der Funktion übergeben und in der Funktion den
Inhalt ggf ändern. Der Returnwert könnte dann anzeigen, daß etwas
geändert wurde bzw. die Funktion erfolgreich war.
Rufus Τ. Firefly schrieb:> Ineffizient ist es, weil bei einer Strukturzuweisung die komplette> Struktur [...] gleich zweimal kopiert [wird], einerseits> bei der Übergabe via return (da wird die lokale Struktur auf den Stack> kopiert (auch wenn sie als automatische Variable eh' schon auf dem Stack> lieg) und andererseits bei der Zuweisung an "Objdat" als Rückgabewert> der Funktion (da wird sie vom Stack wiederum in Objdat kopiert).
Danke für die Info. Effizienz ist mir hier nicht so wichtig, weil Init
über die gesamte Programmlaufzeit ohnehin nur wenige Male aufgerufen
wird, aber es ist gut, das im Hinterkopf zu behalten.
Ich will keinen Zeiger auf ein struct haben- denn dann müßte ich das
Struct schon vor dem Aufruf von Init übergeben. Oder eine dynamische
Speicherverwaltung in Objinit() einbauen. Das macht keinen Spaß.
Aber dann muß ich in Objdata_t eben einen Marker einbauen, der es als
gültig oder ungültig markiert. Geht auch.
Danke für die Diskussion!
Fred schrieb:> Und man sieht dort sehr schön einen großen Vorteil von Rust
Schön, und was hilft das jetzt dem Programmierer mit seinem C Problem?
Rust ist so eine tolle Sprache, daß als erste Treffer in google
"Europapark" erscheint.
Kommt der nächste jetzt mit Algol oder vieleicht Ruby oder Haskell, ...?
Udo Schmitt schrieb:> Wobei das als Zeiger so aber auch nicht funktionieren würde, weil der> Zeiger auf eine lokale Variable zeigt, die auf dem Stack liegt und bei> Verlassen der Funktion nicht mehr gültig ist.
das man dann die stuct mit new anlegen musst, sollte eigentlich klar
sein.
Rufus Τ. Firefly schrieb:> Fred schrieb:>> Und dein return obj; "funktioniert" zwar insofern, als der Compiler es>> übersetzt, es macht aber nicht das, was du sillst und ist ein grober>> Schnitzer.>> Nein. Es ist nicht sonderlich performant, aber es funktioniert im Sinne> des Erfinders.
Wenn der Compiler einigermaßen modern ist und "return value optimization
(1)" kann, wird da gar nichts kopiert, und es ist die effizienteste Art,
die Struktur rauszugeben.
Wenn er das nicht kann, hängt es letztendlich von der Größe der struct
ab und davon, welche Alternative man wählt. Wenn man nämlich in der
Funktion die struct dynamisch allokiert und später wieder freigeben muß,
ist die Kopiererei wahrscheinlich effizienter, sofern die Struktur nicht
allzu riesig ist.
> Ineffizient ist es, weil bei einer Strukturzuweisung die komplette> Struktur kopiert wird; hier wird sie gleich zweimal kopiert, einerseits> bei der Übergabe via return (da wird die lokale Struktur auf den Stack> kopiert (auch wenn sie als automatische Variable eh' schon auf dem Stack> lieg) und andererseits bei der Zuweisung an "Objdat" als Rückgabewert> der Funktion (da wird sie vom Stack wiederum in Objdat kopiert).
Aber nur bei einem schlechten Compiler, denn beides kann heutzutage
problemlos wegoptimiert werden.
(1) http://en.wikipedia.org/wiki/Return_value_optimization
Walter Tarpan schrieb:> Ich will keinen Zeiger auf ein struct haben- denn dann müßte ich das> Struct schon vor dem Aufruf von Init übergeben.
Ja und? Bei deinem Aufruf in dieser Art hast du Speicher als globale
Variable oder lokale in main() oder wo auch immer so oder so schon
reserviert:
Walter Tarpan schrieb:> Objdat = Objinit(Init);
Das Objdat fällt ja nicht vom Himmel, irgendwo hast du es schon
definiert, sonst könntest du es nicht zuweisen.
Rolf Magnus schrieb:> Wenn der Compiler einigermaßen modern ist und "return value optimization> (1)" kann, wird da gar nichts kopiert, und es ist die effizienteste Art,> die Struktur rauszugeben.
Effizienter wäre trotzdem noch der Call by Reference, also über einen
Pointer, oder optimiert der Compiler hier derart, daß Änderungen in der
Funktion direkt in der Zielstruktur (die ausserhalb definiert ist)
gemacht werden?
Udo Schmitt schrieb:> Schön, und was hilft das jetzt dem Programmierer mit seinem C Problem?
Akut nicht viel, aber das ist hier ja auch keine 1:1-Kommunikation.
> Rust ist so eine tolle Sprache, daß als erste Treffer in google> "Europapark" erscheint.
Und bei "Go" erscheint ein Expreß-Kurier, und dann schließlich auf Platz
zwei das Brettspiel.
Zu "C" kommt zuoberst ein Chart der Citigroup-Aktie.
Deine Bewertungsmethodik für Relevanz ist durchaus verbesserungsfähig.
Und dein Gefühl, wann du etwas zu einer Diskussion beiträgst, ebenso.
Peter II schrieb:> das man dann die stuct mit new anlegen musst
Mir ist das klar, dem TO auch?
Wobei ein implizites alloc() in einer Funktion dann beim Nutzer der
Funktion das explizite Wissen darüber erfordert daß diese Funktion das
macht und deshalb schnell zu Memory leaks führen kann.
Das ist eigentlich eher schlechter Stil, wobei man da natürlich immer
das richtige Augenmass braucht und es Ausnahmen gibt.
Fred schrieb:> Deine Bewertungsmethodik für Relevanz ist durchaus verbesserungsfähig.
Gut, dann zeige die vielen tausend Stück Software die damit schon
erfolgreich geschrieben und verkauft wurden, oder die Firmen, die die
Sprache einsetzen, oder die offenen Stellen am Arbeitsmarkt, die diese
Programmiersprache fordern.
Im Ernst, diese Verweise auf Programmiersprachenexoten hilft wahrlich
nicht weiter. Eine weitere Diskussion darüber aber auch nicht :-/
Udo Schmitt schrieb:> Gut, dann zeige die vielen tausend Stück Software die damit schon> erfolgreich geschrieben und verkauft wurden, oder die Firmen, die die> Sprache einsetzen, oder die offenen Stellen am Arbeitsmarkt, die diese> Programmiersprache fordern.
Ich wiederhole mich:
>> Deine Bewertungsmethodik für Relevanz ist durchaus verbesserungsfähig.
Fred schrieb:> Ich wiederhole mich:>>> Deine Bewertungsmethodik für Relevanz ist durchaus verbesserungsfähig.
Rofl,
deine ist wohl: "ich mag das also ist es relevant" :-)
Peter II schrieb:> Hier bietet sich wirklich Übergabe als Zeiger oder Refenz an.> obj Objdata_t;>> if( !Objinit(obj) ) goto error;
Objinit mit Rückgabewert für SUCCESS und FAIL ausstatten. Ist auch eine
Überlegung wert.
Udo Schmitt schrieb:> deine ist wohl: "ich mag das also ist es relevant" :-)
Nein, meine ist "es wird vermutlich einige Leute interessieren".
Es gibt hier durchaus Leser, die nicht alles in industrieller Verwendung
messen. Angeblich sogar Hobbyisten. Gerüchtehalber gar Leute, die sogar
Basic einsetzen. :-)
Fred schrieb:> Nein, meine ist "es wird vermutlich einige Leute interessieren".
Ok, das lass ich gerne auch gelten. Ich habe wohl deinen Post dazu
missverstanden. Klang für mich nach "Rust ist vel besser, also wechsle
dazu" und war wohl eher gemeint als "Übrigens da gibts Rust, kann man
sich bei Interesse mal anschauen".
:-)
Wegstaben Verbuchsler schrieb:> GOTO in C-Programmen!
Gab sogar Bücher die das propagiert haben, als Fehlerabbruch.
Ist allemal besser als 20 mal if (!error) { ... }
bei Steuerungsfunktionen mit mehreren sequentiellen Aufrufen von
Subfunktionen.
Udo Schmitt schrieb:> Ok, das lass ich gerne auch gelten. Ich habe wohl deinen Post dazu> missverstanden. Klang für mich nach "Rust ist vel besser, also wechsle> dazu" und war wohl eher gemeint als "Übrigens da gibts Rust, kann man> sich bei Interesse mal anschauen".> :-)
Genau so. Schön, dann ist ja alles gut. :-)
zu "Rust" als Programmiersprache gibt es nicht mal einen
deutschsprachigen Wikipedia Eintrag. Das sollte genug drüber aussagen,
wie relevant diese Sprache ist.
Professionel uninteressant, und für Hobbyisten wohl auch. Denn als
Hobbyist ist ein wichtiges Bewertungskriterium: wieviele Infos finde ich
darüber im Netz?
Ist ja schön und gut dass es für jedes Problem ein eigenes Werkzeug gibt
und man nicht immer die C oder C++ Brechstange rausholen muss. Aber
solche Insellösungen wie Rust sind dann auch nicht erstrebenswert.
Sorry, mir war fad.
Daniel A. schrieb:>> Laut C-Standard kann man structs ja nicht vergleichen.>> Doch, mitmemcmp(&obj1,&obj2,sizeof(obj_t))==0
Das aber liefert ... unerwartete Ergebnisse, wenn das Alignment ins
Spiel kommt.
Sind nämlich die Strukturelemente nicht an Byte-, sondern an 16- oder
32-Bit-Adressen ausgerichtet, was eben auf 16- oder 32-Bit-Architekturen
üblich ist, dann enthält die Struktur Lücken, in denen Zufallswerte
stehen können.
Und die sorgen dafür, daß so ein Vergleich in die Hose geht.
Rufus Τ. Firefly schrieb:> Und die sorgen dafür, daß so ein Vergleich in die Hose geht.
Ausser man hat die Strukturen vor der Benutzung sauber mit memset
genullt.
Wegstaben Verbuchsler schrieb:> oder, noch schlimmer: GOTO in C-Programmen! ;-)
Ich bin immer offen dafür, neues zu lernen. Insbesondere über
Fehlerbehandlung/robuste Implementierung. Kennst Du eine solide Quelle?
Dann muß ich nicht alle Fehler immer selbst machen.
Udo Schmitt schrieb:> Rolf Magnus schrieb:>> Wenn der Compiler einigermaßen modern ist und "return value optimization>> (1)" kann, wird da gar nichts kopiert, und es ist die effizienteste Art,>> die Struktur rauszugeben.>> Effizienter wäre trotzdem noch der Call by Reference, also über einen> Pointer, oder optimiert der Compiler hier derart, daß Änderungen in der> Funktion direkt in der Zielstruktur (die ausserhalb definiert ist)> gemacht werden?
Ja, genau das ist ja die Idee hinter dieser Optimierung.
Wegstaben Verbuchsler schrieb:> oder, noch schlimmer: GOTO in C-Programmen! ;-)
läßt sich steigern: int anstelle int16_t oder char anstelle uint8_t und
so weiter. Das geradezu teuflische an goto ist, daß es fest im
Grundwortschatz von C enthalten ist ;-)
Die Skale der erreichbaren Unleserlichkeit bei C ist wie die
Richterskale: nach oben offen..
W.S.
W.S. schrieb:> läßt sich steigern: int anstelle int16_t oder char anstelle uint8_t und> so weiter.
Naja, die (u)intXX_t Typen sind auch nicht gerade toll, da stdint.h
diese nicht bereitstellen muss und auf einigen Architekturen teilweise
nicht vorhanden sind. Besser ist da die Verwendung der (u)int_fastXX_t
und (u)int_leastXX_t Typen, die stdint.h zwingend bereitstellen muss.
Nutzt man printf oder ähnliches, sollte man natürlich auch die
Formatierungszeichen aus inttypes.h verwenden.
Die (u)intXX_t Typen verwende ich nur in hardwareabhängigen Funktionen,
die direkt auf Hardware zugreifen.
So ist das ja auch gedacht. Exakte größen braucht man außer für
Memory-Mapped-Register nur zur Kommunikation nach außen (Binäre Files &
Übertragungsprotokolle).