www.mikrocontroller.net

Forum: PC-Programmierung gcc: operation on may be undefined


Autor: Hugo B. (stinkywinky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Gemeinde

Ich verstehe nicht, warum gcc bei folgendem Code motzt:
1263: uint32 tCnt, tDir, tIdx;

1287: for(tCnt = 0; tCnt < NB_TR_CNTS; tCnt++)
1288: {
1289:   for(tDir = 0; tDir < NB_DIRS; tDir++)
1290:   {
1291:     tIdx = 8*tCnt + 4*tDir;
1292:     G_OpData.TravelCnt[tCnt][tDir] =    tBuf[tIdx++]
1293:                                      + (tBuf[tIdx++] << 8)
1294:                                      + (tBuf[tIdx++] << 16)
1295:                                      + (tBuf[tIdx++] << 24);
1296:   }
1297: }

file.c:1295: warning: operation on `tIdx' may be undefined
file.c:1295: warning: operation on `tIdx' may be undefined
file.c:1295: warning: operation on `tIdx' may be undefined

Es hat wohl mit dem Post-Inkrement zu tun. Trotzdem finde ich, dass das 
so in Ordnung ist.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Java wäre das wohl ok. In C isses undefiniert, da niemand weiß, wann 
der um 1 erhöhte Wert wieder an die Variable zurückgeht.
Ein Übersetzer könnte etwa folgendes draus machen:
     G_OpData.TravelCnt[tCnt][tDir] =    tBuf[tIdx]
                                      + (tBuf[tIdx] << 8)
                                      + (tBuf[tIdx] << 16)
                                      + (tBuf[tIdx] << 24);
tIdx += 4;

Es fehlt ein Sequenzpunkt dazwischen. Ansonsten halte ich auch wenig von 
solchen Spielereien.

Lösung:
     G_OpData.TravelCnt[tCnt][tDir] =    tBuf[tIdx + 0]
                                      + (tBuf[tIdx + 1] << 8)
                                      + (tBuf[tIdx + 2] << 16)
                                      + (tBuf[tIdx + 3] << 24);
tIdx += 4;
Übersichtlich und jeder verstehts, ohnes Gehirn zu verknoten.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:

> In Java wäre das wohl ok.

Wie ist das denn in Java definiert?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Es hat wohl mit dem Post-Inkrement zu tun. Trotzdem finde ich, dass das
> so in Ordnung ist.

Ob du das findest, ist aber dem Compiler egal. ;-)
Wie Sven schreibt, fehlt ein Sequenzpunkt zwischen den Inkrements. Das 
Verhalten von Code, der eine Variable mehrmals ändert oder ändert und 
liest, ohne daß dazwischen ein Sequenzpunkt liegt, ist in C undefiniert. 
Daher zurecht die Warnung.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Sven P. schrieb:
>
>> In Java wäre das wohl ok.
>
> Wie ist das denn in Java definiert?
Keine Ahnung, ich erinnere mich nur an so ein hirnverbranntes Beispiel 
für Java, und der Compiler hat keine Warnung ausgespuckt.

Hier isses:
http://www.thestudentroom.co.uk/showthread.php?t=639421
In C/++ wäre das hochgradig undefiniert und totaler Schwachsinn isses 
sowieso.

Autor: Daniel H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, ich habe letzte Nacht kaum geschlafen, die Heizung war kaputt, hab 
seit 7 Uhr Handwerker im Haus, die die Eingangstür wechseln - und Kaffe 
ist das einzige was mich jetzt noch am leben hält ;-) Vielleicht liegt 
es ja daran, dass ich total auf den Schlauch stehe und das Problem nicht 
nachvollziehen kann.
Mein gcc (version 3.4.5 (mingw-vista special)), aufgerufen mit -Wall, 
meckert auf jedenfall nicht. Welche gcc version für welches Target mit 
welchen compiler flags benutzt Du denn? Und wieso ist das Verhalten 
undefiniert? Gibt es deswegen nicht auch die C-Prioritäten? IMHO steht 
da doch: Greife auf das Array tBuff mit dem Index tIdx zu, danach 
inkrementiere tIdx, danach greife auf das Array tBuff mit dem neuen Wert 
von tIdx zu, danach inkrementiere tIdx, danach addiere die Inhalte der 
ersten beiden Array zugriffe usw.

Grüße Daniel

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entscheidend ist nicht, ob der Compiler meckert, sondern was die 
Sprachdefinition hergibt. Und die ist eindeutig: das Verhalten ist 
undefiniert. Weder Prioritäten noch der sogenannte gesunde 
Menschenverstand ändern daran etwas.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel H. schrieb:
> IMHO steht
> da doch: Greife auf das Array tBuff mit dem Index tIdx zu, danach
> inkrementiere tIdx, danach greife auf das Array tBuff mit dem neuen Wert
> von tIdx zu, danach inkrementiere tIdx, danach addiere die Inhalte der
> ersten beiden Array zugriffe usw.
Ne, es steht nirgendwo, WANN tIdx seinen neuen Wert bekommt. Dafür gibts 
ja Sequenzpunkte, und die fehlen hier.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel H. schrieb:
> IMHO steht
> da doch: Greife auf das Array tBuff mit dem Index tIdx zu, danach
> inkrementiere tIdx,

Nein.
Das steht da eben nicht.

Der Compiler ist in seiner Entscheidung frei, wann genau er das 
Inkrementieren durchführen will. Er muss es nur irgendwann machen, ehe 
das nächste Statement beginnt (Exakt gesagt: Vor dem nächsten Sequence 
Point, aber in dem Fall ist das der ';', also der Zeitpunkt an dem das 
nächste Statement beginnt)

Wenn der Compiler will, kann er alle 4 Inkrements bis ans Ende der 
Ausführungskette verschieben.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Daniel: Deine postulierte Abfolge setzt voraus, dass von links nach 
rechts ausgewertet wird, und dass in einem Ausdruck enthaltene 
Zuweisungen in einer bestimmten Reihenfolge entsprechend der Prioritäten 
ausgeführt werden. Dem ist nicht so. Zuweisungen in einem Ausdruck (a++ 
und ++a sind Zuweisungen) sind erst am schon sattsam erwähnten sequence 
point mit Sicherheit durchgeführt, davor kann es sein muss aber nicht 
sein. So ist C nun einmal definiert. Beschwerden bitte an Dennis Ritchie 
richten.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> @Daniel: Deine postulierte Abfolge setzt voraus, dass von links nach
> rechts ausgewertet wird,

Darauf möchte ich noch näher eingehen, weil es wichtig ist.
Oft wird nämlich Operatoren-Reihenfolge mit Auswerte-Reihenfolge 
verwechselt.
Operatoren-Reihenfolge ist definiert.
Es ist zb exakt festgelegt, dass
    a + b + c
als
    ( a + b ) + c
berechnet wird.

Es ist aber nicht festgelegt, in welcher Reihenfolge die Teilausdrücke 
a, b, und c ausgewertet (dh. ein Zahlenwert dafür bestimmt) werden.

Der Compiler kann zuerst c auswerten, dann b und dann a (oder jede 
andere beliebige Reihenfolge) und dann die Teilwerte gemäss

    ( a + b ) + c

zum Gesamtwert zusammenführen.

Das ist mit Auswerte-Reihenfolge gemeint: Die Reihenfolge, in der 
Teilausdrücke bewertet werden.
Wenn die Teilausdrücke Nebeneffekte besitzen (wie zb hier das Inkrement) 
ist alleine dadurch schon ein undefiniertes Verhalten gegeben.
Ein anderes Beispiel:

   result = foo() + bar();

Es ist durch die undefinierte Auswertereihenfolge nicht definiert, ob 
zuerst die Funktion foo() und erst dann die Funktion bar() aufgerufen 
wird, oder umgekehrt. Wenn daher bar() darauf angewiesen ist, dass foo() 
zuerst aufgerufen wird (weil es zb einen Wert für bar() einstellen 
muss), dann hat man hier ein Problem.

Autor: Daniel H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke an alle! Jetzt habe auch ich es geschnallt :-)

Bei a = b + b++; kann das Inkrement z.B vor oder nach der Addition 
erfolgen, was natürlich zu unterschiedlichen Verhalten führt. Sicher ist 
nur, dass b nach dieser Zeile inkrementiert wurde.

Grüße, Daniel

Autor: Stephan M. (stephanm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Sven P. schrieb:
>> In Java wäre das wohl ok.
> Wie ist das denn in Java definiert?

Java arbeitet Ausdrücke strikt von links nach rechts ab.

Stephan

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wiederum ist dann nicht mit der Kurzschluss-Bewertung zu 
verwechseln, bei welcher die Auswertereihenfolge festgelegt ist:
if ( foo() && bar() ) {

}

if ( foo() || bar() ) {

}

In beiden Fällen wird foo() zuerst bewertet. Dadurch lassen sich solche 
Sachen formulieren:
Zeiger p;
if ( (p != NULL) && (p->bla) ) ..

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:
> Das wiederum ist dann nicht mit der Kurzschluss-Bewertung zu
> verwechseln, bei welcher die Auswertereihenfolge festgelegt ist:

Ganz genau.
Geregelt ist das dadurch, dass sowohl && als auch || als Sequence Point 
gelten.

Die wichtigsten Sequence Points sind
* && || und Komma Operator (nit zu verwechseln mit dem normalen Komma)
* beim ? in einem ?: Ausdruck
* Am Ende eines vollständigen Ausdrucks (vulgo: beim ';')
  Dazu zählt aber auch: Der Ausdruck, der ein if, while etc. steuert
* Beim Aufruf einer Funktion, nachdem die Funktionsargumente
  ausgewertet wurden. Aber Achtung: Die Reihenfolge der Auswertung der
  Funktionsargumente ist nach wie vor undefiniert, genauso wie der
  exakte Zeitpunkt, wann Nebeneffekte dabei abgearbeitet werden.
  Definiert ist lediglich, dass Nebeneffekte abgeschlossen sind, wenn
  die Funktion die Kontrolle erhält.
  foo( i++, i++ );
  hat daher undefiniertes Verhalten.
  Und nein: Dieses ',' hier ist nicht der Komma-Operator.


Grob gesagt kann man festhalten:
Der Compiler ist zwischen 2 Sequence-Points frei in seiner Entscheidung, 
in welcher Reihenfolge er was abarbeiten möchte. Normalerweise hat ein 
bestimmter Compiler eine bestimmte Auswertereihenfolge, die sich oft aus 
den Eigenschaften der zugrundeliegenden Hardware ergibt. Zb werden oft 
Funktionsargumente von rechts nach links ausgewertet, weil sie dann in 
der richtigen Reihenfolge auf dem Stack abgelegt werden können. 
Gefährlich wird es erst, wenn man implizit von einer bestimmten 
Auswertereihenfolge ausgeht und das Programm von einem Compiler auf 
einen anderen portiert wird, der eine andere Reihenfolge benutzt.

Autor: Hugo B. (stinkywinky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besten Dank, dieses Forum ist einfach spitze!

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> if ( foo() && bar() ) {
>
> }
>
> if ( foo() || bar() ) {
>
> }
>
>
> In beiden Fällen wird foo() zuerst bewertet.

Deshalb stellen in C das && und das || auch Sequenzpunkte dar.

> Dadurch lassen sich solche
> Sachen formulieren:
> Zeiger p;
> if ( (p != NULL) && (p->bla) ) ..

Theretisch geht sogar das::
  p && p->x++ || printf("Kein p\n");
(zugegebenermaßen arg konstrukiert)

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso, dabei am Rande ein Zitat:

Die Programmiersprache C. Ein Nachschlagewerk.
Regionales Rechenzentrum für Niedersachsen/Leibniz-Universität Hannover, 
Zentralinstitut für angewandte Mathematik, Forschungsgruppe Jülich GmbH:

Dieses Institut hat so ein grünes Heftchen herausgebracht und freut 
sich:
17. unveränderte Auflage, September 2008.
Auflabe: bisher 163.000 Exemplare.

Und in jedem dieser Exemplare steht auf Seite 77 unten:
int i, j;
/* ... */

i = 1;
i = ++i + 1; /* dies ist auch möglich; i hat Wert 3 */

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus schrieb:
>
>   p && p->x++ || printf("Kein p\n");
> 
> (zugegebenermaßen arg konstrukiert)

Garnicht mal. Frag mal Perl-Leute, oder benutz ne anständige Konsole:
cc -o test test.c && ./test

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Sven: Stimmt doch. Es ist möglich, dass "i" danach den Wert 3 hat. Es 
ist natürlich auch möglich, dass "i" danach nicht den Wert 3 hat.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, is natürlich ein klasse Beispiel für so ein Nachschlagewerk.

Genauso schön wie (sinngemäß):
char c;
while ( (c = getc(f)) != EOF) ..

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> @Sven: Stimmt doch. Es ist möglich, dass "i" danach den Wert 3 hat. Es
> ist natürlich auch möglich, dass "i" danach nicht den Wert 3 hat.

You made my day :-)

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>
>>   p && p->x++ || printf("Kein p\n");
>>
>> (zugegebenermaßen arg konstrukiert)
>
> Garnicht mal. Frag mal Perl-Leute, oder benutz ne anständige Konsole:
> cc -o test test.c && ./test

Ist mir schon klar. In Shellskripten ist das recht üblich.
Aus einem Makefile, das ich letzte Woche schrieb:
        @decompyle --verify -o $(dir $<) $< > $(patsubst %.pyc,%.log,$<) 2>&1 && echo ok || ( [ $$? -eq 3 ] && echo verify failed || echo failed; true)

Ich meinte, daß es für C eher konstruiert ist. Da ergibt sich bei dieser 
Art der Verwendung von Operatoren nämlich das Problem, daß sich in C 
nicht jeder Ausdruck als logischer Wert verwenden läßt. Das Beispiel 
klappt nur, weil p->x ein int ist, printf einen int zurückgibt und p 
sich in einen konvertieren läßt.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
p && p->flag || (something_returning_void("Flag kaputt"), 1);

schmunzel

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> i = ++i + 1; /* dies ist auch möglich; i hat Wert 3 */

Bevor ihr alle zu sehr über dieses Beispiel lästert: Kann jemand eine
Auswertereihenfolge angeben, bei der am Ende nicht 3 herauskommt? Mir
fällt spontan jedenfalls keine ein und bin deswegen fast überzeugt, dass
dieser Code nicht undefined ist.

"Fast" deswegen, weil ich noch nicht lange genug überlegt habe ;-)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
i = 1;
temp = i + 1;
i = temp + 1;
i = temp;

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mir fällt spontan jedenfalls keine ein und bin deswegen fast
> überzeugt, dass dieser Code nicht undefined ist.

Nehme alles zurück, da exakt dieses Beispiel im ISO-Standard als
Beispiel für einen undefinierten Ausdruck angegeben ist :)

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> i = ++i + 1;

++i wird zu 2 ausgewertet, also steht da:

i = 2 + 1;

Danach könnte das i = i + 1 ausgeführt werden.

==> i = 4;

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> i = 1;
> temp = i + 1;
> i = temp + 1;
> i = temp;

Ja, genau, das wäre das Gegenbeispiel.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yalu schrieb:
>> i = ++i + 1; /* dies ist auch möglich; i hat Wert 3 */
>
> Bevor ihr alle zu sehr über dieses Beispiel lästert: Kann jemand eine
> Auswertereihenfolge angeben, bei der am Ende nicht 3 herauskommt?
i = 1;

zwischen = i + 1;
i = zwischen + 1;
i = zwischen;

/* i ist 2 */

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> i = ++i + 1; /* dies ist auch möglich; i hat Wert 3 */
>
> Bevor ihr alle zu sehr über dieses Beispiel lästert: Kann jemand eine
> Auswertereihenfolge angeben, bei der am Ende nicht 3 herauskommt?

Spielt eigentlich keine Rolle. Laut ISO-C braucht i danach gar keinen 
Wert zu haben. Das Programm darf an der Stelle auch einfach 
stehenbleiben oder danach beliebigen Blödsinn veranstalten. Nicht der 
Wert gilt als undefiniert, sondern das gesamte Verhalten des Programms.

> Mir fällt spontan jedenfalls keine ein und bin deswegen fast überzeugt,
> dass dieser Code nicht undefined ist.

Er könnte z.B. beim Operator++ den inkrementierten Wert zurückgeben, da 
1 dazuzählen und an i zuweisen. Danach wird dann das vorher gemerkte 
Ergebnis vom Operator++ nach i geschrieben. Dann steht danach 2 in i.

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> temp = i + 1;
> i = temp + 1;
> i = temp;

Sven P. schrieb:
> zwischen = i + 1;
> i = zwischen + 1;
> i = zwischen;

@Sven P.: Danke für die Übersetzung des Codes von A. K. ins Deutsche.
Spätestens jetzt habe ich's wirklich kapiert ;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yalu schrieb:
>> i = ++i + 1; /* dies ist auch möglich; i hat Wert 3 */
>
> Bevor ihr alle zu sehr über dieses Beispiel lästert: Kann jemand eine
> Auswertereihenfolge angeben, bei der am Ende nicht 3 herauskommt?


Du machst hier noch immer den Fehler, dass du ++i als eine Einheit 
ansiehst, die 2 Aktion macht
  i erhöhen
  mit dem erhöhten Wert weiterrechnen

Tatsächlich ist die Sache aber etwas anders
* ++i
  liefert den um 1 erhöhten Wert von i

  das ist der Haupteffekt dieses Ausdrucks

* der Nebeneffekt dieses Ausdrucks ist es, dass dieser um 1 erhöhte
  Wert wieder in i abgespeichert wird.

Nur ist in C nicht festgelegt, wann genau Nebeneffekte abgearbeitet 
werden. Spätestens mit dem nächsten Sequence Point muss der Nebeneffekt 
ausgeführt worden sein. Aber bis dorthin darf der Compiler den 
Nebeneffekt schieben, wie er lustig ist.
Der Ausdruck ++i (oder i++) besteht also aus 2 Effekten, die zeitlich 
nichts miteinander zu tun haben. Auch bei i++ hindert zb keine C-Regel 
den Compiler daran, zunächst mit der Inkrementierung zu beginnen um 
dann, wenn der Wert des Ausdrucks benötigt wird, von diesem 
Zwischenergebnis wieder 1 abzuziehen. Theoretisch wäre das möglich, auch 
wenn es natürlich kein Compiler so machen wird.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fazit:
Wenn man eine bestimmte Reihenfolge der Auswertung erzwingen will (und 
man hat nicht den Fall && ||) dann ist es am besten, selbst die 
Anweisung in Teilanweisungen aufzusplitten. Dadurch erlangt man die 
Kontrolle über die Auswertereihenfolge

    result = foo() + bar();

vs

    result = foo();
    result += bar();

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:
> Ja, is natürlich ein klasse Beispiel für so ein Nachschlagewerk.
>
> Genauso schön wie (sinngemäß):
>
> char c;
> while ( (c = getc(f)) != EOF) ..
> 

Yep. Das ist auch so ein Klassiker wie zb auch
   while( !feof( f ) ) {
     fread( ...

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> while ( (c = getc(f)) != EOF) ..

öhm...  grübel *denk*

Wenn ich mal ganz kleinlaut fragen darf, was stimmt mit dem Beispiel 
nicht? ;)

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich mal ganz kleinlaut fragen darf, was stimmt mit dem Beispiel
> nicht? ;)

Da stimmen zwei Sachen nicht. Eine in dem Teil, den du zitiert hast, 
eine im anderen Teil.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
getc() gibt einen Integer zurück oder ein Zeichen. (c = getc(..)) ist 
wegen c vom Typ char. Dadurch kann EOF (-1) nicht mehr vom Zeichen #255 
unterschieden werden.

Karl:
An deinem Beispiel ist mir grad nicht klar, was schief gehen soll --

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:
> getc() gibt einen Integer zurück oder ein Zeichen. (c = getc(..)) ist
> wegen c vom Typ char. Dadurch kann EOF (-1) nicht mehr vom Zeichen #255
> unterschieden werden.

AHA! Das hab ich doch glatt übersehen.

Sven P. schrieb:
> Karl:
> An deinem Beispiel ist mir grad nicht klar, was schief gehen soll --

Ich könnte mir höchstens vorstellen, dass das EOF-Flag noch nicht 
gesetzt ist, wenn eine leere Datei geöffnet wird. Und damit wird die 
Schleife trotzdem einmal ausgeführt, obwohl nichts gelesen werden kann.

Zitat:
> This indicator is generally set by a previous operation on the stream that > 
reached the End-of-File.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Karl:
> An deinem Beispiel ist mir grad nicht klar, was schief gehen soll --

feof(f) wird erst wahr, nachdem man versucht hat, über das Dateiende 
hinaus zu lesen. Die Schleife wird also einmal zu oft durchlaufen.

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ist ein Beispiel mit einer etwas asführlicherer Erklärung:

http://www.cprogramming.com/faq/cgi-bin/smartfaq.c...

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso, die Schiene ist gemeint.

Autor: Bartli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Warnung selber ist eigentlich auch amüsant:

"warning: operation on `blubb' may be undefined"

Wieso "may be"? Gemäss Standard ist das Verhalten undefiniert.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, der Standard sagt, es ist undefiniert. Das hindert aber niemanden, 
der einen Compiler baut, es in irgendeiner Weise zu festzulegen. Im 
Standard steht ja nicht 'must be undefined'.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:
> Im
> Standard steht ja nicht 'must be undefined'.

Genau, der Compiler muss in dem Fall, wenn er standardgemäß arbeiten 
soll, eine zufällige binäre Sequenz in den Code einbauen ;)

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wieso "may be"? Gemäss Standard ist das Verhalten undefiniert.

Ich nehme an, daß die Erkennung dieses Falls nicht 100% zuverlässig ist, 
da sie doch schon ziemlich extensive Analyse des Codeflusses erfordert. 
Es könnte also einen Fall geben, in dem die Warnung kommt, obwohl alles 
in Ordnung ist. Deshalb "may be".

Autor: Bartli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das hindert aber niemanden, der einen Compiler baut,
> es in irgendeiner Weise zu festzulegen.

Und was hat er davon? Gar nichts, ausser zusätzlichen Implementations- 
und Dokumentationsaufwand, weil der nächste Compiler folgende Variante 
implementiert hat:

> Genau, der Compiler muss in dem Fall, wenn er standardgemäß arbeiten
> soll, eine zufällige binäre Sequenz in den Code einbauen

So gesehen ist der Wortlaut "is undefined" das einzig Vernünftige. Wenns 
mir mal langweilig genug ist, schreib ich einen Bugreport.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bartli schrieb:
>> Das hindert aber niemanden, der einen Compiler baut,
>> es in irgendeiner Weise zu festzulegen.
>
> Und was hat er davon? Gar nichts, ausser zusätzlichen Implementations-
> und Dokumentationsaufwand, weil der nächste Compiler folgende Variante
> implementiert hat:
Du kannst davon ausgehen, dass fast jeder Compiler es in irgendeiner 
Weise definiert. Nur die allerwenigsten werden bei solch einer 
Konstruktion einen Zufallsgenerator bemühen.

Ansonsten schließe ich mich Rolf Magnus an.

Autor: Bartli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Du kannst davon ausgehen, dass fast jeder Compiler es in irgendeiner
> Weise definiert.

Nee, definitiv nicht. Aufgrund ihrer Implementation dürften die meisten 
Compiler ein deterministisches Verhalten haben, aber du glaubst doch 
nicht im Ernst das da jemand hingeht, sich zuerst überm ganzen Problem 
den Kopf zerbricht und dann erst das Verhalten definiert und 
dokumentiert?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bartli schrieb:
>> Du kannst davon ausgehen, dass fast jeder Compiler es in irgendeiner
>> Weise definiert.
>
> Nee, definitiv nicht. Aufgrund ihrer Implementation dürften die meisten
> Compiler ein deterministisches Verhalten haben, aber du glaubst doch
> nicht im Ernst das da jemand hingeht, sich zuerst überm ganzen Problem
> den Kopf zerbricht und dann erst das Verhalten definiert und
> dokumentiert?
Nö, hab ich das behauptet? Aber du siehst ja, die Java-Leute haben sich 
zuerst den Kopf darüber zerbrochen und das Verhalten dann fest 
definiert.

Laut C-Standard musst du auch damit rechnen, dass ein char 43 Bits hat, 
davon aber 13 Bits nicht zum Wert gehören. Ein Zeiger ist dann 7 chars 
breit und ein Funktionszeiger darf auch 5mal so groß sein, wie ein 
Datenzeiger. Außerdem sind char, short, int und long alle gleichbreit.

Und? Das wäre eine vollkommen Standard-C-Konforme Umgebung.

Autor: Bartli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schön, Sven. Und jetzt?

Trotzdem glaube ich nicht, dass gcc's Implementation auf eine bewusst 
definierte Art arbeitet, und die Formulation "may be" ist und bleibt 
Quark.

Was anderes ist es im Fall von "blah may be used uninitialized", aber 
darum gehts nicht, ebenso wenig um 47 Bits breite chars.

Und was Java betrifft: da gabs noch keine Altlasten in Form von 
Compilern die lange vor irgendwelchen Standards existierten. Da hat sich 
die Mühe das Zeugs vorwegs zu definieren sogar gelohnt.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Laut C-Standard musst du auch damit rechnen, dass ein char 43 Bits hat,
> davon aber 13 Bits nicht zum Wert gehören.

Nicht ganz. Bei char müssen alle Bits zum Wert beitragen.

> Ein Zeiger ist dann 7 chars breit und ein Funktionszeiger darf auch 5mal
> so groß sein, wie ein Datenzeiger. Außerdem sind char, short, int und
> long alle gleichbreit.
>
> Und? Das wäre eine vollkommen Standard-C-Konforme Umgebung.

Ja. Wenn das auf der Zielplattform sinnvoll wäre, warum auch nicht?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.