Discussion:
Undefined behavior in sehr einfachem Programm
Add Reply
Thomas Koenig
2018-09-15 10:46:04 UTC
Antworten
Permalink
Spezifikation:

Ein Programm soll eine Ganzzahl von standard input einlesen lesen,
um eins erhöhen und auf standard output ausgeben. Für den Fall,
dass dies nicht möglich ist, soll ein Fehlschlag an die Umgebung
signalisiert werden, ansonsten Erfolg. Das Programm soll der
C89-Norm entsprechen.

Lösungsansatz: Das folgende Progrämmchen.

#include <stdio.h>
#include <stdlib.h>

int main()
{
long i;
if (scanf("%ld", &i) != 1)
exit (EXIT_FAILURE);

i++;
printf("%ld\n", i);
exit (EXIT_SUCCESS);
}

Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.

Wie käme man da drum rum?
Helmut Schellong
2018-09-15 11:49:51 UTC
Antworten
Permalink
Post by Thomas Koenig
Ein Programm soll eine Ganzzahl von standard input einlesen lesen,
um eins erhöhen und auf standard output ausgeben. Für den Fall,
dass dies nicht möglich ist, soll ein Fehlschlag an die Umgebung
signalisiert werden, ansonsten Erfolg. Das Programm soll der
C89-Norm entsprechen.
Lösungsansatz: Das folgende Progrämmchen.
#include <stdio.h>
#include <stdlib.h>
int main()
{
long i;
if (scanf("%ld", &i) != 1)
exit (EXIT_FAILURE);
i++;
printf("%ld\n", i);
exit (EXIT_SUCCESS);
}
Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.
Ich wüßte nicht, warum.
Wenn Format-Spezifizierer und Typ zusammenpassen, ist's okay.

Nimm doch return v; anstatt exit!
'main()' verstößt gegen den Standard!
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
David Seppi
2018-09-16 06:36:31 UTC
Antworten
Permalink
Post by Helmut Schellong
Nimm doch return v; anstatt exit!
Das ist nach dem Standard doch eh äquivalent.
Post by Helmut Schellong
'main()' verstößt gegen den Standard!
Inwiefern?
--
David Seppi
1220 Wien
Helmut Schellong
2018-09-16 09:54:50 UTC
Antworten
Permalink
Post by David Seppi
Post by Helmut Schellong
Nimm doch return v; anstatt exit!
Das ist nach dem Standard doch eh äquivalent.
Trotzdem ist das in der main-Funktion unsinnig.
So etwas sollte nicht vorgemacht werden.
Sonst sieht man nach einer Weile keine Verwendung
von return mehr.
Genau so, wie die permanent falschen main-Typen.
Siehe unten.
Post by David Seppi
Post by Helmut Schellong
'main()' verstößt gegen den Standard!
Inwiefern?
Der Standard definiert genau zwei main-Typen:

5.1.2.2.1 Program startup
The function called at program startup is named main.
The implementation declares no prototype for this function.
It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv,
though any names may be used, as they are local to the function
in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;10) or in some other implementation-defined manner.

The special case of an unnamed parameter of type void
as the only item in the list specifies that the function
has no parameters.


int main();
finde ich nicht unter den definierten main-Typen.

Der Standard schreibt bei '(void)', daß die Funktion
keine Parameter hat.
Der Standard schreibt bei '()', daß die Funktion
ohne Parameter-Spezifikation ist.


Ich habe schon mal gesehen, daß andere Funktionen
so: serve(void) definiert wurden, main() jedoch nicht!
Das liegt daran, daß fast alle deutschen C-Bücher
main falsch definiert zeigen, bis auf mein Buch
und sehr wenige andere.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
David Seppi
2018-09-17 07:57:32 UTC
Antworten
Permalink
Helmut Schellong schrieb:

[return vs exit]
Post by Helmut Schellong
Trotzdem ist das in der main-Funktion unsinnig.
So etwas sollte nicht vorgemacht werden.
Sonst sieht man nach einer Weile keine Verwendung
von return mehr.
Und? Wo ist das Problem?
Post by Helmut Schellong
Der Standard schreibt bei '(void)', daß die Funktion
keine Parameter hat.
Der Standard schreibt bei '()', daß die Funktion
ohne Parameter-Spezifikation ist.
Das stimmt doch nicht. Obiges gilt nur für die Deklaration einer
Funktion, wenn diese nicht Teil der Definition ist, also zB
"int foo();". Bei einer Funktionsdefinition bedeutet eine leere
Liste aber ausdrücklich "keine Argumente".
"int main() {...}" hat also keine Argumente.
Post by Helmut Schellong
Ich habe schon mal gesehen, daß andere Funktionen
so: serve(void) definiert wurden, main() jedoch nicht!
Das liegt daran, daß fast alle deutschen C-Bücher
main falsch definiert zeigen, bis auf mein Buch
und sehr wenige andere.
Das liegt eher daran, daß Du den Standard nicht lesen kannst.
§ 3.5.4.3 ist da recht eindeutig.
--
David Seppi
1220 Wien
Helmut Schellong
2018-09-17 13:20:44 UTC
Antworten
Permalink
Post by David Seppi
[return vs exit]
Post by Helmut Schellong
Trotzdem ist das in der main-Funktion unsinnig.
So etwas sollte nicht vorgemacht werden.
Sonst sieht man nach einer Weile keine Verwendung
von return mehr.
Und? Wo ist das Problem?
Ähh, was?!
In main() soll also ruhig exit(v); statt return v;
verwendet werden?!
Die Funktion exit() existiert, um auch in anderen Funktionen
als main() direkt ein Programmende herbeiführen zu können.

Der Standard verwendet jedenfalls 'return' in main():
-----------------------------------------------------
int main(void)
{
uintmax_t i = UINTMAX_MAX;
wprintf(L"The largest integer value is %020"
PRIxMAX "\n", i);
return 0;
}
-----------------------------------------------------
Obwohl es geht - ich wüßte nicht, warum ich dort
exit(0); statt return 0; verwenden sollte.
Post by David Seppi
Post by Helmut Schellong
Der Standard schreibt bei '(void)', daß die Funktion
keine Parameter hat.
Der Standard schreibt bei '()', daß die Funktion
ohne Parameter-Spezifikation ist.
Das stimmt doch nicht. Obiges gilt nur für die Deklaration einer
Funktion, wenn diese nicht Teil der Definition ist, also zB
"int foo();". Bei einer Funktionsdefinition bedeutet eine leere
Liste aber ausdrücklich "keine Argumente".
"int main() {...}" hat also keine Argumente.
Was ich schrieb, stimmt.
Der Standard macht einen Unterschied zwischen '(void)' und '()'.
Mehr hatte ich nicht geschrieben und wollte ich auch nicht aussagen.

Seit es Prototypen gibt, verwende ich diese strikt.
Die 'Future language directions' geben mir recht.

Ich verwende '()' nicht, sondern '(void)' oder '(typ, ..)'.
Der Standard verwendet auch 'main(void) {/*...*/}' bei Definition.

Ich deklariere doch nicht 'int f();', um nachfolgend fleißig
'i= f(ty, k, qfrom);' usw. aufzurufen.

--------------------------------------------------------------------
6.7.6.3 Function declarators (including prototypes)
Constraints

Absatz 14:
An identifier list declares only the identifiers of the parameters
of the function.
An empty list in a function declarator that is part of a definition
of that function specifies that the function has no parameters.
The empty list in a function declarator that is not part of a
definition of that function specifies that no information about
the number or types of the parameters is supplied.145)

Absatz 16:
EXAMPLE 1 The declaration
int f(void), *fip(), (*pfi)();
declares a function f with no parameters returning an int, a
function fip with no parameter specification returning a pointer
to an int, and a pointer pfi to a function with
no parameter specification returning an int.

6.11 Future language directions

6.11.6 Function declarators
The use of function declarators with empty parentheses
(not prototype-format parameter type declarators)
is an obsolescent feature.

6.11.7 Function definitions
The use of function definitions with separate parameter identifier
and declaration lists
(not prototype-format parameter type and identifier declarators)
is an obsolescent feature.
--------------------------------------------------------------------
Post by David Seppi
Post by Helmut Schellong
Ich habe schon mal gesehen, daß andere Funktionen
so: serve(void) definiert wurden, main() jedoch nicht!
Das liegt daran, daß fast alle deutschen C-Bücher
main falsch definiert zeigen, bis auf mein Buch
und sehr wenige andere.
Das liegt eher daran, daß Du den Standard nicht lesen kannst.
§ 3.5.4.3 ist da recht eindeutig.
Erstens gibt es 3.5.4.3 nicht.
Zweitens hast Du meinen Absatz offenbar gar nicht verstanden.

Ich schrieb, daß andere C-Programmierer, Funktionen, die
keine Parameter haben sollen, beispielsweise kkk(void)
mmm(void) nnn(void) ooo(void) definierten, jedoch
'main' so: main() definierten.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2018-09-17 13:52:30 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by David Seppi
Post by Helmut Schellong
Der Standard schreibt bei '(void)', daß die Funktion
keine Parameter hat.
Der Standard schreibt bei '()', daß die Funktion
ohne Parameter-Spezifikation ist.
Das stimmt doch nicht. Obiges gilt nur für die Deklaration einer
Funktion, wenn diese nicht Teil der Definition ist, also zB
"int foo();". Bei einer Funktionsdefinition bedeutet eine leere
Liste aber ausdrücklich "keine Argumente".
"int main() {...}" hat also keine Argumente.
Was ich schrieb, stimmt.
Nein.
Post by Helmut Schellong
--------------------------------------------------------------------
6.7.6.3 Function declarators (including prototypes)
^^^^^^^^^^^
Post by Helmut Schellong
Constraints
An identifier list declares only the identifiers of the parameters
of the function.
An empty list in a function declarator that is part of a definition
of that function specifies that the function has no parameters.
The empty list in a function declarator that is not part of a
definition of that function specifies that no information about
the number or types of the parameters is supplied.145)
Das oben zitierte gilt fuer Funktions*deklarationen* (sprich "Prototypen"),
nicht fuer Funktions*defitionen*. Wuerdest du main vor der Definition noch
einmal de3klarieren, muesstest du es tatsaechlich mit einem der im Standard
genannten Prototypen tun (und diese Deklaration muesste mit einem ";" abge-
schlossen sein). Dein Vorredner schrieb aber nicht von einer Deklaration
von main, sondern von der *Defition* (das, was eben *kein* Prototyp sondern
das Ding mit richtig Code darin ud *OHNE* abschliessendes Semikolon ist).
Fuer die Definition gilt der von dir zitierte Absatz *nicht*, denn der be-
schaeftigt sich mit Funktions*deklarationen*, nicht mit Funktions-
*definitionen* ...
Post by Helmut Schellong
EXAMPLE 1 The declaration
int f(void), *fip(), (*pfi)();
declares a function f with no parameters returning an int, a
function fip with no parameter specification returning a pointer
to an int, and a pointer pfi to a function with
no parameter specification returning an int.
Auch hier: Funktions*deklarationen*, nicht Funktions*defitionen*.
Post by Helmut Schellong
6.11 Future language directions
6.11.7 Function definitions
The use of function definitions with separate parameter identifier
and declaration lists
(not prototype-format parameter type and identifier declarators)
is an obsolescent feature.
--------------------------------------------------------------------
Hier ist das erste3 mal von Funktions*defitionen* die Rede, aber *nicht*
von der Bedeutung einer leeren Parameterliste ...

Wenn du (im Gegensatz zum Standard) *nicht* zwischen Deklaration und
Definition unterscheiden kannst, liegt das nicht am Standard sondern
an dir ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Stefan Ram
2018-09-17 14:24:25 UTC
Antworten
Permalink
Post by Juergen Ilse
Das oben zitierte gilt fuer Funktions*deklarationen* (sprich "Prototypen"),
nicht fuer Funktions*defitionen*.
Ersten sind /alle/ Funktionsdefinitionen laut
N2176 6.7p5 auch Funktionsdeklarationen.

Zweitens sind laut N2176 6.2.1p2 /nicht/ alle
Funktionsdefinition auch Prototypen.
Stefan Ram
2018-09-17 23:07:27 UTC
Antworten
Permalink
Zum Unterschied "»int main(){}« versus »int main( void ){}«":

»int main(){}« definiert im Gegensatz zu »int main( void ){}«
keinen Prototyp.

N2176 kennt zwei Arten von Funktionsdeklaratoren:

- in den Klammern kann eine parameter-type-list stehen
(Prototypstil),

- in den Klammern kann eine optionale identifier-list
stehen (K&R-Stil).

Quelle: N2176, 6.7.6 Declarators, p1; zusammen mit
6.9.1 Function definitions, p1

Eine parameter-type-list kann /nicht/ leer sein.

Quelle: ebenfalls N2176, 6.7.6 Declarators, p1

Daher sind leere Klammern der K&R-Stil (optionale
identifier-list) und deklarieren somit /keinen Prototyp/
(vergleiche N2176, 6.9.1p7), obwohl sie durchaus angeben,
daß die Funktion keine Parameter hat (N2176 6.7.6.3 Function
declarators p14, Satz 2)!

»void« ist eine »parameter-type-list« und definiert laut
6.9.1 Function definitions, p7, Satz 2 einen Prototyp und
gibt außerdem laut N2176 6.7.6.3 Function declarators p10
(wie leere Klammern) an, daß die Funktion keine Parameter hat.

Leere Klammern und »void« geben also beide an, daß die
Funktion keine Parameter hat, aber nur »void« definiert
auch einen Prototyp.
Helmut Schellong
2018-09-18 11:56:09 UTC
Antworten
Permalink
Post by Stefan Ram
[...]
Leere Klammern und »void« geben also beide an, daß die
Funktion keine Parameter hat, aber nur »void« definiert
auch einen Prototyp.
Wobei () nur für verbundene Funktionsdefinitionen gilt.
Auf jeden Fall sollte void verwendet werden.
Sonst ignoriert man void und Prototypen-Stil (seit 1989)
und benutzt stattdessen ein obsoletes Merkmal.


Ich habe noch Namenlisten der alten Form.
Allerdings kombiniert mit modernen Prototypen:

static void CpA(struct vec *, int,int,byte *,int *,int *);
static void CpPA(struct vec *, int,int,int,int *,int *);

static void CpA(vc, nw, fd, from, aip, app)
struct vec *vc;
int nw, fd, *aip,*app;
byte *from;
{

static void CpPA(vc, m, C, A, aip, app)
struct vec *vc;
int m, C,A, *aip,*app;
{
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Helmut Schellong
2018-09-17 15:42:54 UTC
Antworten
Permalink
Post by Juergen Ilse
Post by Helmut Schellong
Post by David Seppi
Post by Helmut Schellong
Der Standard schreibt bei '(void)', daß die Funktion
keine Parameter hat.
Der Standard schreibt bei '()', daß die Funktion
ohne Parameter-Spezifikation ist.
Das stimmt doch nicht. Obiges gilt nur für die Deklaration einer
Funktion, wenn diese nicht Teil der Definition ist, also zB
"int foo();". Bei einer Funktionsdefinition bedeutet eine leere
Liste aber ausdrücklich "keine Argumente".
"int main() {...}" hat also keine Argumente.
Was ich schrieb, stimmt.
Nein.
Doch.

Was schrieb ich?:
-----------------------------------------------------
Der Standard schreibt bei '(void)', daß die Funktion
keine Parameter hat.
Der Standard schreibt bei '()', daß die Funktion
ohne Parameter-Spezifikation ist.
-----------------------------------------------------

Was steht im Standard?:
-----------------------------------------------------
EXAMPLE 1 The declaration
int f(void), *fip(), (*pfi)();
declares a function f with no parameters returning an int, a
function fip with no parameter specification returning a pointer
-----------------------------------------------------

Da haben wir es also:
Es stimmt also, was ich schrieb!
Post by Juergen Ilse
Post by Helmut Schellong
--------------------------------------------------------------------
6.7.6.3 Function declarators (including prototypes)
^^^^^^^^^^^
Post by Helmut Schellong
Constraints
An identifier list declares only the identifiers of the parameters
of the function.
An empty list in a function declarator that is part of a definition
of that function specifies that the function has no parameters.
The empty list in a function declarator that is not part of a
definition of that function specifies that no information about
the number or types of the parameters is supplied.145)
Das oben zitierte gilt fuer Funktions*deklarationen* (sprich "Prototypen"),
Nein, es gilt auch für Definitionen!:

"An empty list in a function declarator that is part of a definition"
"The empty list in a function declarator that is not part of a definition"

Das beschreibt der Standard hier:
---------------------------------
int foo()
{
int bar();
return 3;
}

foo() deklariert eine Funktion, die keine Parameter hat.
bar() deklariert eine Funktion, ohne gegebene Parameter-Spezifikation.
---------------------------------

Die Überschrift:
"6.7.6.3 Function declarators (including prototypes)"
betitelt lediglich keine Definition einer Funktions-Definition.
Das ist alles.

Eine Funktions-Definition enthält stets auch ihre eigene Deklaration.
Post by Juergen Ilse
nicht fuer Funktions*defitionen*. Wuerdest du main vor der Definition noch
einmal de3klarieren, muesstest du es tatsaechlich mit einem der im Standard
genannten Prototypen tun (und diese Deklaration muesste mit einem ";" abge-
schlossen sein). Dein Vorredner schrieb aber nicht von einer Deklaration
von main, sondern von der *Defition* (das, was eben *kein* Prototyp sondern
das Ding mit richtig Code darin ud *OHNE* abschliessendes Semikolon ist).
Fuer die Definition gilt der von dir zitierte Absatz *nicht*, denn der be-
schaeftigt sich mit Funktions*deklarationen*, nicht mit Funktions-
*definitionen* ...
Siehe oben.
Eine Funktions-Definition enthält stets auch ihre eigene Deklaration.
Post by Juergen Ilse
Post by Helmut Schellong
EXAMPLE 1 The declaration
int f(void), *fip(), (*pfi)();
declares a function f with no parameters returning an int, a
function fip with no parameter specification returning a pointer
to an int, and a pointer pfi to a function with
no parameter specification returning an int.
Auch hier: Funktions*deklarationen*, nicht Funktions*defitionen*.
Ja - und?
'(void)' hat eine andere Semantik als '()'.
Nur das ist hier geschrieben.
Nur das wollte ich hier aussagen.
Post by Juergen Ilse
Post by Helmut Schellong
6.11 Future language directions
6.11.7 Function definitions
The use of function definitions with separate parameter identifier
and declaration lists
(not prototype-format parameter type and identifier declarators)
is an obsolescent feature.
--------------------------------------------------------------------
Hier ist das erste3 mal von Funktions*defitionen* die Rede, aber *nicht*
von der Bedeutung einer leeren Parameterliste ...
Ja und?
Habe ich irgendwo besonders auf Funktionsdefinitionen abgehoben?

Ich schrieb:
-----------------------------------------------------
Der Standard schreibt bei '(void)', daß die Funktion
keine Parameter hat.
Der Standard schreibt bei '()', daß die Funktion
ohne Parameter-Spezifikation ist.
-----------------------------------------------------

So steht das da, und im Standard steht das sinngemäß genau so.
Wo ist das Verständnisproblem?
Post by Juergen Ilse
Wenn du (im Gegensatz zum Standard) *nicht* zwischen Deklaration und
Definition unterscheiden kannst, liegt das nicht am Standard sondern
an dir ...
Tss, tss.
Ich habe schon 1981 in PEARL programmiert, welche die
Schlüsselwörter 'DECLARE / DCL' hat.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2018-09-17 16:36:24 UTC
Antworten
Permalink
Post by Helmut Schellong
In main() soll also ruhig exit(v); statt return v;
verwendet werden?!
Klar, die beiden sind äquivalent.

Siehe C89, 5.1.2.2.3:

# A return from the initial call to the main function is equivalent
# to calling the exit function with the value returned by the main
# function as its arguments.
Post by Helmut Schellong
Die Funktion exit() existiert, um auch in anderen Funktionen
als main() direkt ein Programmende herbeiführen zu können.
Dafür braucht man sie tatsächlich.

In main kann man das so halten wie der sprichwörtliche
Dachdecker.
Stilbesipiele in der Norm sind nicht bindend. Ich verwende
z.B. auch eine Einrückung :-)
Helmut Schellong
2018-09-17 17:44:58 UTC
Antworten
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
In main() soll also ruhig exit(v); statt return v;
verwendet werden?!
Klar, die beiden sind äquivalent.
Es ist klar, daß jede Library-Funktion überall
aufgerufen werden kann.
Post by Thomas Koenig
# A return from the initial call to the main function is equivalent
# to calling the exit function with the value returned by the main
# function as its arguments.
Post by Helmut Schellong
Die Funktion exit() existiert, um auch in anderen Funktionen
als main() direkt ein Programmende herbeiführen zu können.
Dafür braucht man sie tatsächlich.
In main kann man das so halten wie der sprichwörtliche
Dachdecker.
Funktionsmäßig ja.
Ich würde exit() in main() aber nur verwenden, falls ich
main() rekursiv aufgerufen hätte.
Überwiegend aus Gründen des Stils.
Post by Thomas Koenig
Stilbesipiele in der Norm sind nicht bindend. Ich verwende
z.B. auch eine Einrückung :-)
Natürlich ist das nicht bindend.
Beispiele sind im Standard aber durchaus normativ.
'return' in main() ist üblich, nicht mehr, nicht weniger.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
David Seppi
2018-09-17 19:20:47 UTC
Antworten
Permalink
Post by Helmut Schellong
Ähh, was?!
In main() soll also ruhig exit(v); statt return v;
verwendet werden?!
Warum nicht?
Post by Helmut Schellong
Die Funktion exit() existiert, um auch in anderen Funktionen
als main() direkt ein Programmende herbeiführen zu können.
Sie kann aber auch in main() verwendet werden.
Warum sollte das nicht getan werden?
Post by Helmut Schellong
Obwohl es geht - ich wüßte nicht, warum ich dort
exit(0); statt return 0; verwenden sollte.
* um copy-paste-Fehler zu reduzieren.
Vielleicht lagerst Du ja irgendwann größere Codeblöcke
in andere Funktionen aus und übersiehst dabei ein return,
das in ein exit umgeschrieben werden müßte.
* um den Gültigkeitsbereich lokaler Variablen nicht zu
verlassen. Eventuell greifen ja durch atexit(3) registrierte
Funktionen darauf zu.
* um die Lesbarkeit zu erhöhen.
Post by Helmut Schellong
Was ich schrieb, stimmt.
Der Standard macht einen Unterschied zwischen '(void)' und '()'.
Mehr hatte ich nicht geschrieben und wollte ich auch nicht aussagen.
Doch, hast Du. Der Unterschied besteht nämlich nur bei Deklarationen,
die nicht Teil einer Definition sind. Gerade bei "int main() {...}"
besteht der Unterschied also nicht. Wieso unterstellst Du dann UB?
Post by Helmut Schellong
--------------------------------------------------------------------
6.7.6.3 Function declarators (including prototypes)
Constraints
An identifier list declares only the identifiers of the parameters
of the function.
# An empty list in a function declarator that is part of a definition
# of that function specifies that the function has no parameters.

Ich habe Dir die relevante Stelle markiert.
Post by Helmut Schellong
Erstens gibt es 3.5.4.3 nicht.
Ja, sorry, da hätte ich mich nicht auf den Draft verlassen sollen.
Ich meinte die von Dir oben zitierte Stelle.
--
David Seppi
1220 Wien
Rainer Weikusat
2018-09-17 20:05:37 UTC
Antworten
Permalink
[...]
Post by David Seppi
Post by Helmut Schellong
Was ich schrieb, stimmt.
Der Standard macht einen Unterschied zwischen '(void)' und '()'.
Mehr hatte ich nicht geschrieben und wollte ich auch nicht aussagen.
Doch, hast Du. Der Unterschied besteht nämlich nur bei Deklarationen,
die nicht Teil einer Definition sind. Gerade bei "int main() {...}"
besteht der Unterschied also nicht. Wieso unterstellst Du dann UB?
Weil man dieser Ansicht sein kann. Der relevante Textabschnitt ist

It [main] shall be defined with a return type of int and with no
parameters:

int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv,
though any names may be used, as they are local to the function
in which they are declared):

int main(int argc, char *argv[]) { /* ... */ }

or equivalent;9) or in some other implementation-defined manner.

Das "oder gleichwertig" ("or equivalent") bezieht sich auf die zweite
Form, was in einer Fussnote nochmals erlaeutert: Anstatt int kann auch
ein typedef-Name fuer int gebraucht werden und anstelle von char *argv[]
darf auch char **argv benutzt werden.

Daraus kann man schliessen, das

int main() { ... }

nicht erlaubt ist, obwohl es gleichwertig zu

int main(void) { ... }

ist.
Helmut Schellong
2018-09-17 22:43:41 UTC
Antworten
Permalink
Post by Rainer Weikusat
[...]
Daraus kann man schliessen, das
int main() { ... }
nicht erlaubt ist, obwohl es gleichwertig zu
int main(void) { ... }
ist.
UB hatte ich dazu nicht unterstellt, sondern ich nannte
int main() { ... }
falsch.

Das Wort 'falsch' ist hier zu simpel und wohl übertrieben.

Jedenfalls sind alle Listen-Konstruktionen hierzu, die nicht
vom Prototypen-Stil sind, offiziell obsolet.


D( parameter-type-list )
or
D( identifier-list opt )

An i d e n t i f i e r l i s t declares only the
identifiers of the parameters of the function.
An empty list in a function declarator that is part of a definition
of that function specifies that the function has no parameters.
The empty list in a function declarator that is not part of a
definition of that function specifies that no information
about the number or types of the parameters is supplied.145)

An identifier list in a function declarator that is not part
of a definition of that function shall be empty.


Vollkommen klar ist die Sache nicht für mich.
Die Absätze beziehen sich offenbar nur auf die Namenliste
der ganz alten Form.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2018-09-18 14:40:32 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Rainer Weikusat
[...]
Daraus kann man schliessen, das
int main() { ... }
nicht erlaubt ist, obwohl es gleichwertig zu
int main(void) { ... }
ist.
UB hatte ich dazu nicht unterstellt, sondern ich nannte
int main() { ... }
falsch.
Das Wort 'falsch' ist hier zu simpel und wohl übertrieben.
Ich halte es (das Adjektiv) fuer falsch. Man kann

int main() { ... }

als undefiniertes Verhalten ansehen, weil die Variante mit (void)
grammatisch Teil eines shall-Satzes ist. Wenigstens schliesst der
Wortlaut des Normtextes das nicht aus. Falls man nicht dieser Ansicht
ist, koennte man hoechstens dagegen anfuehren, das irgendjemand die
Definition mit () fuer veraltet haelt. Was sich vermutlich ueber alles
sagen laesst, das aelter als ein paar Monate ist. Aber dadurch wird es
nicht (sachlich) falsch.

Man kann hier andersherum argumentieren: Falls man

int main(void) { ... }

benutzt, ist das Verhalten jedenfalls definiert, es gibt also keinen
guten Grund, das nicht zu tun.
Helmut Schellong
2018-09-18 16:18:59 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Helmut Schellong
Das Wort 'falsch' ist hier zu simpel und wohl übertrieben.
Ich halte es (das Adjektiv) fuer falsch. Man kann
int main() { ... }
als undefiniertes Verhalten ansehen, weil die Variante mit (void)
grammatisch Teil eines shall-Satzes ist. Wenigstens schliesst der
Wortlaut des Normtextes das nicht aus. Falls man nicht dieser Ansicht
ist, koennte man hoechstens dagegen anfuehren, das irgendjemand die
Definition mit () fuer veraltet haelt. Was sich vermutlich ueber alles
sagen laesst, das aelter als ein paar Monate ist. Aber dadurch wird es
nicht (sachlich) falsch.
Man kann hier andersherum argumentieren: Falls man
int main(void) { ... }
benutzt, ist das Verhalten jedenfalls definiert, es gibt also keinen
guten Grund, das nicht zu tun.
Ja, zumal es keine Mühe macht.

Erstaunlich ist, daß im Standard zu sehen ist:

int main()
{
size_t size;
size = fsize3(10);
return 0;
}

int main()
{
double b[4][308];
addscalar(4, 2, b, 2.17);
return 0;
}

int main(void)
{
uintmax_t i = UINTMAX_MAX;
wprintf(L"The largest integer value is %020" PRIxMAX "\n", i);
return 0;
}

Übrigens überall mit 'return' und nicht 'exit'.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Helmut Schellong
2018-09-17 22:05:47 UTC
Antworten
Permalink
Post by David Seppi
Post by Helmut Schellong
Ähh, was?!
In main() soll also ruhig exit(v); statt return v;
verwendet werden?!
Warum nicht?
Weil es nicht üblich ist.
Post by David Seppi
Post by Helmut Schellong
Die Funktion exit() existiert, um auch in anderen Funktionen
als main() direkt ein Programmende herbeiführen zu können.
Sie kann aber auch in main() verwendet werden.
Warum sollte das nicht getan werden?
Weil es nicht üblich ist.
Post by David Seppi
Post by Helmut Schellong
Was ich schrieb, stimmt.
Der Standard macht einen Unterschied zwischen '(void)' und '()'.
Mehr hatte ich nicht geschrieben und wollte ich auch nicht aussagen.
Doch, hast Du. Der Unterschied besteht nämlich nur bei Deklarationen,
die nicht Teil einer Definition sind. Gerade bei "int main() {...}"
besteht der Unterschied also nicht. Wieso unterstellst Du dann UB?
Nein.
Einen Unterschied gibt es zwischen Deklarationen '(void) <> ()'
wie auch zwischen
Deklarationen, die nicht Teil einer Definition sind '()'
und
Deklarationen, die Teil einer Definition sind '()'.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Elias Schwerdtfeger
2018-09-15 14:20:10 UTC
Antworten
Permalink
Post by Thomas Koenig
Lösungsansatz: Das folgende Progrämmchen.
#include <stdio.h>
#include <stdlib.h>
int main()
{
long i;
if (scanf("%ld", &i) != 1)
exit (EXIT_FAILURE);
Bis hierher ist alles so weit in Ordnung, aber dann schlägt...
Post by Thomas Koenig
i++;
...der mögliche Overflow zu. Wenn die Eingabe LONG_MAX ist, dann ist der
Wert in i hinterher undefiniert.
Post by Thomas Koenig
printf("%ld\n", i);
Achtung! Auch, wenn es kaum vorkommt, printf() kann fehlschlagen. (Zum
Beispiel in einer Pipe oder weil der Datenträger voll ist).
Post by Thomas Koenig
exit (EXIT_SUCCESS);
}
Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.
Wie käme man da drum rum?
Ungeprüfter, geschwätzig formulierter Vorschlag:

--[snip]--
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int
main ()
{
long i;

if (scanf ("%ld", &i) != 1)
return EXIT_FAILURE; /* Malformed input */

if (i == LONG_MAX)
return EXIT_FAILURE; /* Overflow */

i++;

if (printf("%ld\n", i) < 0)
return EXIT_FAILURE; /* Output failed */

return EXIT_SUCCESS;
}
--[snap]--

Ich will nicht ausschließen, dass ein lint noch etwas zum Meckern
findet, zum Beispiel, weil die uninitialisierte Variable i benutzt wird,
aber hier sollte es kein undefiniertes Verhalten geben. Mein splint hat
auch nichts auszusetzen -- außer natürlich, ich hänge --strict dran,
aber diesen Warnungsdurchfall will sich wohl niemand geben, der nicht
unbedingt muss.

Alternativ könnte man den alten Wert von i in einer Variablen old_i
speichern und nach dem Inkrementieren schauen, ob er größer geworden
ist, aber das setzt einen Rollover bei Interger-Überläufen voraus, der
nach meinem Kenntnisstand nicht im Standard garantiert wird.
Helmut Schellong
2018-09-15 15:33:07 UTC
Antworten
Permalink
Post by Elias Schwerdtfeger
Post by Thomas Koenig
Lösungsansatz: Das folgende Progrämmchen.
#include <stdio.h>
#include <stdlib.h>
int main()
{
long i;
if (scanf("%ld", &i) != 1)
exit (EXIT_FAILURE);
Bis hierher ist alles so weit in Ordnung, aber dann schlägt...
Post by Thomas Koenig
i++;
...der mögliche Overflow zu. Wenn die Eingabe LONG_MAX ist, dann ist der
Wert in i hinterher undefiniert.
Post by Thomas Koenig
printf("%ld\n", i);
Achtung! Auch, wenn es kaum vorkommt, printf() kann fehlschlagen. (Zum
Beispiel in einer Pipe oder weil der Datenträger voll ist).
Post by Thomas Koenig
exit (EXIT_SUCCESS);
}
Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.
Aber nicht im Zusammenhang mit dem '+'-Operator.
Es _kann_ hier Trap-Repräsentationen geben.
Das ist aber etwas ganz anderes als UB.

Unter x86 gibt es gar kein problematisches Verhalten:
1# echo $((~0))
-1
2# echo $((~0+1))
0
3# echo $((~0+2))
1
4# echo $((~0>>1))
9223372036854775807
5# echo $(([~0>>1]+1))
-9223372036854775808
6# echo $(([~0>>1]+2))
-9223372036854775807
7# echo $(([~0>>1]-1))
9223372036854775806
8#
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Bastian Blank
2018-09-15 16:07:17 UTC
Antworten
Permalink
Du hast UB sehr gut umschrieben. Da vorzeichenbehaftete Integer in C
kein definiertes Overflowverhalten haben, ist es halt UB.

Bastian
Helmut Schellong
2018-09-15 17:24:15 UTC
Antworten
Permalink
Post by Bastian Blank
Du hast UB sehr gut umschrieben. Da vorzeichenbehaftete Integer in C
kein definiertes Overflowverhalten haben, ist es halt UB.
Nein.
Wenn der Standard bei anderen Operatoren UB zuordnet, jedoch
beim Operator '+' nicht, kann man nicht einfach den Standard
überschreiben und doch UB an '+' zuordnen.

Ein Trap ist ein definierter Mechanismus.

Das Overflowverhalten bei vorzeichenbehafteten Integern
ist definiert.
Es gibt lediglich mehr als ein definiertes Verhalten, im
Unterschied zu unsigned.
Das Verhalten ist implementations-'definiert'.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2018-09-15 20:29:48 UTC
Antworten
Permalink
Post by Helmut Schellong
Das Overflowverhalten bei vorzeichenbehafteten Integern
ist definiert.
Nicht, wenn man z.B. bei gcc -fsanitize=undefined eingibt
(siehe anderer Post).

Bist du der Meinung diese Option verstoße gegen die C-Norm?
Helmut Schellong
2018-09-15 21:56:33 UTC
Antworten
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
Das Overflowverhalten bei vorzeichenbehafteten Integern
ist definiert.
Nicht, wenn man z.B. bei gcc -fsanitize=undefined eingibt
(siehe anderer Post).
Bist du der Meinung diese Option verstoße gegen die C-Norm?
Nein, gar nicht.
Der Standard schreibt, wie ich bereits schrieb, von
implementations-definiertem Verhalten.

UB gibt es allerdings nicht bei additiven Operatoren.


scanf:
If there are insufficient arguments for the format, the
behavior is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.

Integer:
Which of these applies is implementation-defined, as is whether
the value with sign bit 1 and all value bits zero (for the first two),
or with sign bit and all value bits 1 (for ones’ complement), is
a trap representation or a normal value.
In the case of sign and magnitude and ones’ complement, if this
representation is a normal value it is called a negative zero.

It is unspecified whether these cases actually generate
a negative zero or a normal zero, and whether a negative zero
becomes a normal zero when stored in an object.
If the implementation does not support negative zeros, the behavior
of the &, |, ^, ~, <<, and >> operators with operands
that would produce such a value is undefined.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Helmut Schellong
2018-09-15 22:05:50 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
Das Overflowverhalten bei vorzeichenbehafteten Integern
ist definiert.
Nicht, wenn man z.B. bei gcc -fsanitize=undefined eingibt
(siehe anderer Post).
Bist du der Meinung diese Option verstoße gegen die C-Norm?
Nein, gar nicht.
Der Standard schreibt, wie ich bereits schrieb, von
implementations-definiertem Verhalten.
UB gibt es allerdings nicht bei additiven Operatoren.
[...]
Nachreichung:
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Bastian Blank
2018-09-16 10:16:55 UTC
Antworten
Permalink
Post by Helmut Schellong
Das Overflowverhalten bei vorzeichenbehafteten Integern
ist definiert.
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren. Für den C++-Standard wurde sogar explizit darüber
diskutiert und eine dementsprechende Änderung abgelehnt, siehe
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r3.html

Bastian
Helmut Schellong
2018-09-16 10:23:34 UTC
Antworten
Permalink
Post by Bastian Blank
Post by Helmut Schellong
Das Overflowverhalten bei vorzeichenbehafteten Integern
ist definiert.
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren. Für den C++-Standard wurde sogar explizit darüber
diskutiert und eine dementsprechende Änderung abgelehnt, siehe
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r3.html
Ich habe das bereits zitiert.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Ram
2018-09-16 12:52:46 UTC
Antworten
Permalink
Post by Bastian Blank
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren.
Ich finde hier in N2176, 6.5 Expressions:

|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.

Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Rainer Weikusat
2018-09-16 13:39:39 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Bastian Blank
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren.
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
'Exceptional condition' ist durch die C-Norm nicht definiert, allerdings
legt die Verwendung im Text soetwas wie einen Overflow-Trap nahe *und*
*nicht* die gcc-Interpretation "Ich finde das aber aussergewoehnlich!".

Spielt aber keine Rolle: Genau wie 'strict aliasing' ist das ein
ueberfluessiges Feature, das man deaktivieren kann.
Ralf Damaschke
2018-09-16 18:38:43 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
'Exceptional condition' ist durch die C-Norm nicht definiert, allerdings
legt die Verwendung im Text soetwas wie einen Overflow-Trap nahe *und*
*nicht* die gcc-Interpretation "Ich finde das aber aussergewoehnlich!".
Die zitierte Stelle *ist* als Definition von /exceptional condition/
gekennzeichnet. Und hier kann im Prinzip alles geschehen (im
Gegensatz zur einfachen Zuweisung zu großer Werte an signed integer).
Helmut Schellong
2018-09-16 20:18:42 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
'Exceptional condition' ist durch die C-Norm nicht definiert, allerdings
legt die Verwendung im Text soetwas wie einen Overflow-Trap nahe *und*
*nicht* die gcc-Interpretation "Ich finde das aber aussergewoehnlich!".
Die zitierte Stelle *ist* als Definition von /exceptional condition/
gekennzeichnet. Und hier kann im Prinzip alles geschehen (im
Gegensatz zur einfachen Zuweisung zu großer Werte an signed integer).
Jedoch andere Definitionen des Standards, die sich nicht allgemein
auf beliebige Ausdrücke und beliebige Operatoren beziehen, sondern
speziell auf signed Integer und Operator '+', können hierdurch
nicht ungültig werden.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2018-09-16 21:19:05 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
'Exceptional condition' ist durch die C-Norm nicht definiert, allerdings
legt die Verwendung im Text soetwas wie einen Overflow-Trap nahe *und*
*nicht* die gcc-Interpretation "Ich finde das aber aussergewoehnlich!".
Die zitierte Stelle *ist* als Definition von /exceptional condition/
gekennzeichnet. Und hier kann im Prinzip alles geschehen (im
Gegensatz zur einfachen Zuweisung zu großer Werte an signed integer).
Die C-Norm sagt nichts ueber "typographische Konvention" (wie
Kursivschrift) im Fliesstext und benutzt den Begriff auch noch in
anderem Zusammenhang:

Floating constants are converted to internal format as if at
translation-time. The conversion of a floating constant shall
not raise an exceptional condition or a floating- point
exception at execution time.
[6.4.4.2|5]

C is compatible with LIA-1's trap requirements for arithmetic
operations, but not for math library functions (which are not
permitted to generate any externally visible exceptional
conditions). An implementation can provide an alternative of
notification
[H.3.1.2|1]
Ralf Damaschke
2018-09-17 01:08:39 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Ralf Damaschke
Die zitierte Stelle *ist* als Definition von /exceptional condition/
gekennzeichnet. Und hier kann im Prinzip alles geschehen (im
Gegensatz zur einfachen Zuweisung zu großer Werte an signed integer).
Die C-Norm sagt nichts ueber "typographische Konvention" (wie
Kursivschrift) im Fliesstext und benutzt den Begriff auch noch in
Oh doch, das sagt sie. In "3. Terms, definitions, and symbols" steht:

| Other terms are defined where they appear in /italic type/ [...]
Helmut Schellong
2018-09-16 19:56:28 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Bastian Blank
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren.
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
erklärst Du für ungültig?:

6.2.6.2 Integer types
Absatz 2:
Which of these applies is implementation-defined, as is whether
the value with sign bit 1 and all value bits zero (for the first two),
or with sign bit and all value bits 1 (for ones¿ complement), is
a trap representation or a normal value.
In the case of sign and magnitude and ones¿ complement, if this
representation is a normal value it is called a negative zero.
Absatz 3:
It is unspecified whether these cases actually generate
a negative zero or a normal zero, and whether a negative zero
becomes a normal zero when stored in an object.
Absatz 4:
If the implementation does not support negative zeros, the behavior
of the &, |, ^, ~, <<, and >> operators with operands
that would produce such a value is undefined.

6.3.1.3 Signed and unsigned integers
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.

6.5.6 Additive operators
The result of the binary + operator is the sum of the operands.
The result of the binary - operator is the difference resulting
from the subtraction of the second operand from the first.

Es steht dort _nichts_ zu UB oder Traps oder Overflow oder
implem.-definiertem Verhalten!
Es folgt Pointer-Arithmetik.


6.11.6 Function declarators
The use of function declarators with empty parentheses
(not prototype-format parameter type declarators)
is an obsolescent feature.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-17 01:28:33 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Stefan Ram
Post by Bastian Blank
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren.
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Die gelten natürlich auch und widersprechen dem obigen Absatz nicht.
Post by Helmut Schellong
6.2.6.2 Integer types
Irrelevant, am Thema vorbei.
Post by Helmut Schellong
6.3.1.3 Signed and unsigned integers
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.
Es geht hier um die Konvertierung (üblicherweise bei einer Zuweisung)
eines bereits vorliegenden Wertes, nicht um die Ausführung einer
Operation.
Post by Helmut Schellong
6.5.6 Additive operators
The result of the binary + operator is the sum of the operands.
The result of the binary - operator is the difference resulting
from the subtraction of the second operand from the first.
Es steht dort _nichts_ zu UB oder Traps oder Overflow oder
implem.-definiertem Verhalten!
Es folgt Pointer-Arithmetik.
Da braucht hier auch nichts zu Overflow stehen, da dies der zitierte
Abschnitt im allgemeinen Teil von 6.5 bereits regelt.
Post by Helmut Schellong
6.11.6 Function declarators
The use of function declarators with empty parentheses
(not prototype-format parameter type declarators)
is an obsolescent feature.
Vielleicht bringst Du demnächst noch ein Shakespeare-Zitat?
Helmut Schellong
2018-09-17 11:42:46 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Stefan Ram
Post by Bastian Blank
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren.
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Die gelten natürlich auch und widersprechen dem obigen Absatz nicht.
Post by Helmut Schellong
6.2.6.2 Integer types
Irrelevant, am Thema vorbei.
Nein, das sind total relevante Texte.
Es sind sogar die relevantesten Texte zum Thema.
Dort werden die Wendepunkte zum Überlauf beschrieben
und potentiell ungültige Werte durch bestimmte Operatoren,
wobei der Operator '+' dort nicht aufgeführt ist.

Der Standard verwendet im normativen Teil von 6. Language
das Wort 'Overflow' offenbar nicht.
Das scheint viele zur Verzweiflung zu bringen.
Post by Ralf Damaschke
Post by Helmut Schellong
6.3.1.3 Signed and unsigned integers
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.
Es geht hier um die Konvertierung (üblicherweise bei einer Zuweisung)
eines bereits vorliegenden Wertes, nicht um die Ausführung einer
Operation.
Das spielt keine Rolle; Der Absatz ist gültig und relevant.
Außerdem ist eine Konvertierung eine Operation.
Der Absatz definiert, was passieren muß, wenn Werte nicht
repräsentierbar sind.
Post by Ralf Damaschke
Post by Helmut Schellong
6.5.6 Additive operators
The result of the binary + operator is the sum of the operands.
The result of the binary - operator is the difference resulting
from the subtraction of the second operand from the first.
Es steht dort _nichts_ zu UB oder Traps oder Overflow oder
implem.-definiertem Verhalten!
Es folgt Pointer-Arithmetik.
Da braucht hier auch nichts zu Overflow stehen, da dies der zitierte
Abschnitt im allgemeinen Teil von 6.5 bereits regelt.
Das ist falsch, da im Operatoren-Kapitel oftmals ein UB zugeordnet
wird - dies jedoch nicht bei den additiven Operatoren.

6.5 Expressions
Some operators (the unary operator ~, and the binary operators
<<, >>, &, ^, and |, collectively described as bitwise operators)
are required to have operands that have integer type.
These operators yield values that depend on the internal
representations of integers, and have implementation-defined
and undefined aspects for signed types.

Und auch hier ist der Operator '+' nicht aufgeführt.
Weiterhin wird Bezug zur Integer-Repräsentation genommen, deren
Beschreibung für Dich nicht relevant ist.
Post by Ralf Damaschke
Post by Helmut Schellong
6.11.6 Function declarators
The use of function declarators with empty parentheses
(not prototype-format parameter type declarators)
is an obsolescent feature.
Vielleicht bringst Du demnächst noch ein Shakespeare-Zitat?
Nein, aber Du und andere sollten mal lernen, wie man grundsätzlich
Standards semantisch korrekt liest.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-17 18:18:05 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Die gelten natürlich auch und widersprechen dem obigen Absatz nicht.
Post by Helmut Schellong
6.2.6.2 Integer types
Irrelevant, am Thema vorbei.
Nein, das sind total relevante Texte.
Es sind sogar die relevantesten Texte zum Thema.
Allenfalls für Dich, wenn Du versuchst, die wert-manipulierenden
Operationen auf Bit-Fummelei herunterzubrechen.
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
6.3.1.3 Signed and unsigned integers
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.
Es geht hier um die Konvertierung (üblicherweise bei einer Zuweisung)
eines bereits vorliegenden Wertes, nicht um die Ausführung einer
Operation.
Das spielt keine Rolle; Der Absatz ist gültig und relevant.
Außerdem ist eine Konvertierung eine Operation.
Der Absatz definiert, was passieren muß, wenn Werte nicht
repräsentierbar sind.
Post by Ralf Damaschke
Post by Helmut Schellong
6.5.6 Additive operators
Es steht dort _nichts_ zu UB oder Traps oder Overflow oder
implem.-definiertem Verhalten!
Es folgt Pointer-Arithmetik.
Da braucht hier auch nichts zu Overflow stehen, da dies der zitierte
Abschnitt im allgemeinen Teil von 6.5 bereits regelt.
Das ist falsch, da im Operatoren-Kapitel oftmals ein UB zugeordnet
wird - dies jedoch nicht bei den additiven Operatoren.
Natürlich kann operator-spezifisches UB nur dort und nicht im
allgemeinen Teil, der für sie alle gilt, beschrieben werden.
Post by Helmut Schellong
6.5 Expressions
Some operators (the unary operator ~, and the binary operators
<<, >>, &, ^, and |, collectively described as bitwise operators)
are required to have operands that have integer type.
These operators yield values that depend on the internal
representations of integers, and have implementation-defined
and undefined aspects for signed types.
Und auch hier ist der Operator '+' nicht aufgeführt.
Weiterhin wird Bezug zur Integer-Repräsentation genommen, deren
Beschreibung für Dich nicht relevant ist.
Die Addition ist nunmal unabhängig von Deinem Lieblingsthema der
bitweisen Darstellung von Integer-Typen.
Post by Helmut Schellong
Nein, aber Du und andere sollten mal lernen, wie man grundsätzlich
Standards semantisch korrekt liest.
Lustig, diesen Vorwurf ausgerechnet von Dir zu hören.
Helmut Schellong
2018-09-17 21:52:11 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
Das ist falsch, da im Operatoren-Kapitel oftmals ein UB zugeordnet
wird - dies jedoch nicht bei den additiven Operatoren.
Natürlich kann operator-spezifisches UB nur dort und nicht im
allgemeinen Teil, der für sie alle gilt, beschrieben werden.
In allgemeinen Teilen werden _auch_ mehrere Operatoren
mit ihren Wirkungen (UB) beschrieben.
Post by Ralf Damaschke
Post by Helmut Schellong
6.5 Expressions
Some operators (the unary operator ~, and the binary operators
<<, >>, &, ^, and |, collectively described as bitwise operators)
are required to have operands that have integer type.
These operators yield values that depend on the internal
representations of integers, and have implementation-defined
and undefined aspects for signed types.
Und auch hier ist der Operator '+' nicht aufgeführt.
Weiterhin wird Bezug zur Integer-Repräsentation genommen, deren
Beschreibung für Dich nicht relevant ist.
Die Addition ist nunmal unabhängig von Deinem Lieblingsthema der
bitweisen Darstellung von Integer-Typen.
Mein Lieblingsthema - wußte ich bisher nicht.
Der Absatz nach '6.5 Expressions' ist jedenfalls relevant
und aufschlußreich.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-18 22:24:49 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Das ist falsch, da im Operatoren-Kapitel oftmals ein UB zugeordnet
wird - dies jedoch nicht bei den additiven Operatoren.
Natürlich kann operator-spezifisches UB nur dort und nicht im
allgemeinen Teil, der für sie alle gilt, beschrieben werden.
In allgemeinen Teilen werden _auch_ mehrere Operatoren
mit ihren Wirkungen (UB) beschrieben.
Die Alternative wäre, den Sermon an zig Stellen zu kopieren.
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
6.5 Expressions
Some operators (the unary operator ~, and the binary operators
<<, >>, &, ^, and |, collectively described as bitwise operators)
are required to have operands that have integer type.
These operators yield values that depend on the internal
representations of integers, and have implementation-defined
and undefined aspects for signed types.
Und auch hier ist der Operator '+' nicht aufgeführt.
Weiterhin wird Bezug zur Integer-Repräsentation genommen, deren
Beschreibung für Dich nicht relevant ist.
Für die Bit-Operationen schon, aber nicht für den hier diskutierten Fall!
Sie wird nicht gebraucht, um zu verstehen, dass durch Addition Werte
entstehen können, die nicht in einem 'signed long' dargestellt werden
können.
Post by Helmut Schellong
Post by Ralf Damaschke
Die Addition ist nunmal unabhängig von Deinem Lieblingsthema der
bitweisen Darstellung von Integer-Typen.
Mein Lieblingsthema - wußte ich bisher nicht.
Der Absatz nach '6.5 Expressions' ist jedenfalls relevant
und aufschlußreich.
Ja, vor allem p5, der _alle_ Ausdrücke betrifft, während p4 - wie Du
selbst schon bemerktest - nichts mit Addition zu tun hat.
Helmut Schellong
2018-09-19 17:23:23 UTC
Antworten
Permalink
[...]
Post by Ralf Damaschke
Post by Stefan Ram
6.5 Expressions
[...]
Post by Ralf Damaschke
Post by Stefan Ram
Und auch hier ist der Operator '+' nicht aufgeführt.
Weiterhin wird Bezug zur Integer-Repräsentation genommen, deren
Beschreibung für Dich nicht relevant ist.
Für die Bit-Operationen schon, aber nicht für den hier diskutierten Fall!
Sie wird nicht gebraucht, um zu verstehen, dass durch Addition Werte
entstehen können, die nicht in einem 'signed long' dargestellt werden
können.
*** Undefined behavior in sehr einfachem Programm ***

Das ist der Titel dieses Threads.
Und es geht um Addition von 1.

Genau dazu schrieb ich, daß es kein UB gibt
bei signed Integer und Addition.

Um etwas anderes geht es mir hier nicht.

Die erste Antwort (von mir) auf die Thread-Eröffnung:
=============================================================
Post by Ralf Damaschke
Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.
Ich wüßte nicht, warum.
Wenn Format-Spezifizierer und Typ zusammenpassen, ist's okay.

Nimm doch return v; anstatt exit!
'main()' verstößt gegen den Standard!
=============================================================
Und meine Antwort ist zutreffend.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-19 23:53:41 UTC
Antworten
Permalink
Post by Helmut Schellong
[...]
Post by Ralf Damaschke
Post by Stefan Ram
6.5 Expressions
[...]
Post by Ralf Damaschke
Post by Stefan Ram
Und auch hier ist der Operator '+' nicht aufgeführt.
Weiterhin wird Bezug zur Integer-Repräsentation genommen, deren
Beschreibung für Dich nicht relevant ist.
Für die Bit-Operationen schon, aber nicht für den hier diskutierten Fall!
Sie wird nicht gebraucht, um zu verstehen, dass durch Addition Werte
entstehen können, die nicht in einem 'signed long' dargestellt werden
können.
*** Undefined behavior in sehr einfachem Programm ***
Das ist der Titel dieses Threads.
Und es geht um Addition von 1.
Genau dazu schrieb ich, daß es kein UB gibt
bei signed Integer und Addition.
Um etwas anderes geht es mir hier nicht.
Doch es ist falsch (6.5p5). LONG_MAX+1 lässt sich nicht in einem
long darstellen.
Post by Helmut Schellong
=============================================================
Post by Ralf Damaschke
Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.
Ich wüßte nicht, warum.
Wenn Format-Spezifizierer und Typ zusammenpassen, ist's okay.
Auch das wurde bereits widerlegt (7.21.6.2p10).
Post by Helmut Schellong
Nimm doch return v; anstatt exit!
'main()' verstößt gegen den Standard!
=============================================================
Diesen Aspekt nehme ich aus. Dazu habe ich nichts geschrieben und
werde es auch nicht.
Post by Helmut Schellong
Und meine Antwort ist zutreffend.
Ganz im Gegenteil.
Helmut Schellong
2018-09-20 02:01:09 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
*** Undefined behavior in sehr einfachem Programm ***
Das ist der Titel dieses Threads.
Und es geht um Addition von 1.
Genau dazu schrieb ich, daß es kein UB gibt
bei signed Integer und Addition.
Um etwas anderes geht es mir hier nicht.
Doch es ist falsch (6.5p5). LONG_MAX+1 lässt sich nicht in einem
long darstellen.
Ja, aber es gibt deshalb kein UB.
Post by Ralf Damaschke
Post by Helmut Schellong
=============================================================
Post by Thomas Koenig
Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.
Ich wüßte nicht, warum.
Wenn Format-Spezifizierer und Typ zusammenpassen, ist's okay.
Auch das wurde bereits widerlegt (7.21.6.2p10).
Nein, wurde nicht widerlegt.
In Bezug auf UB ist's okay, weil es kein UB gibt.

Wo weist der Standard einer Addition (x+y) UB zu?
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Claus Reibenstein
2018-09-20 06:47:13 UTC
Antworten
Permalink
Post by Helmut Schellong
Wo weist der Standard einer Addition (x+y) UB zu?
Ich habe hier leider nur den 99er, nicht den 89er. Im 99er steht in 6.5
Expressions Abschnitt 5 (und im 89er wird sicher Ähnliches, wenn nicht
sogar dasselbe stehen):

"If an exceptional condition occurs during the evaluation of an
expression (that is, if the result is not mathematically defined or not
in the range of representable values for its type), the behavior is
undefined."

LONG_MAX + 1 ist eine solche Ausnahmebedingung, weil das Ergebnis nicht
mehr als long darstellbar ist. Ergo: UB.

Und nun kommst Du: Wo steht, dass dies ausgerechnet für die Addition
_nicht_ gelten soll?

Gruß
Claus
Rainer Weikusat
2018-09-20 14:27:23 UTC
Antworten
Permalink
Post by Claus Reibenstein
Post by Helmut Schellong
Wo weist der Standard einer Addition (x+y) UB zu?
Ich habe hier leider nur den 99er, nicht den 89er. Im 99er steht in 6.5
Expressions Abschnitt 5 (und im 89er wird sicher Ähnliches, wenn nicht
"If an exceptional condition occurs during the evaluation of an
expression (that is, if the result is not mathematically defined or not
in the range of representable values for its type), the behavior is
undefined."
LONG_MAX + 1 ist eine solche Ausnahmebedingung, weil das Ergebnis nicht
mehr als long darstellbar ist. Ergo: UB.
Das Leute das fuer aussergewoehnlich halten, heisst nicht, dass es das
auch ist. Das kaeme auf die Hardware an, die eine solche Addition
ausfuehrt. Ein Ganzahlbereichsueberlauf *kann* als Fehler angesehen
werden. Oder als etwas anderes, zB koennte die Addition saettigend sein
oder auf einem Restklassenring definiert. In beiden Faellen ist das
Resultat als long darstellbar. Die semantische Definition von + ist
lediglich

The result of the binary + operator is the sum of the operands.

Das hier eine Addition definiert auf der Menge der Zahlen gemeint ist
(fuer Ganzahladdition) obwohl sowas auf jedem Computer, der Ganzahltypen
fester Breite unterstuetzt, eine Unmoeglichkeit ist (genaugenommen sogar
auf jedem, der bloss endlich viel Speicher hat, dh auf jedem Computer)
ist lediglich eine Annahme, die manche Leute aus irgendwelchen Gruenden
machen moechten.

Da eine so definierte Operation technisch nicht implementierbar ist,
kann man diese Interpretation als "offensichtlich unsinnig" verwerfen.
Sie ist auch kontraer zu existierender Praxis seit Tag 1 C wo "Addition"
immer bedeutet hat "was auch immer die benutzte Hardware hier zur
Verfuegung stellt".
Ralf Damaschke
2018-09-21 00:13:22 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Helmut Schellong
Wo weist der Standard einer Addition (x+y) UB zu?
Ich habe hier leider nur den 99er, nicht den 89er. Im 99er steht in 6.5
Expressions Abschnitt 5 (und im 89er wird sicher Ähnliches, wenn nicht
"If an exceptional condition occurs during the evaluation of an
expression (that is, if the result is not mathematically defined or not
in the range of representable values for its type), the behavior is
undefined."
LONG_MAX + 1 ist eine solche Ausnahmebedingung, weil das Ergebnis nicht
mehr als long darstellbar ist. Ergo: UB.
Das Leute das fuer aussergewoehnlich halten, heisst nicht, dass es das
auch ist. Das kaeme auf die Hardware an, die eine solche Addition
ausfuehrt. Ein Ganzahlbereichsueberlauf *kann* als Fehler angesehen
werden. Oder als etwas anderes, zB koennte die Addition saettigend sein
oder auf einem Restklassenring definiert. In beiden Faellen ist das
Resultat als long darstellbar. Die semantische Definition von + ist
lediglich
The result of the binary + operator is the sum of the operands.
Das hier eine Addition definiert auf der Menge der Zahlen gemeint ist
(fuer Ganzahladdition) obwohl sowas auf jedem Computer, der Ganzahltypen
fester Breite unterstuetzt, eine Unmoeglichkeit ist (genaugenommen sogar
auf jedem, der bloss endlich viel Speicher hat, dh auf jedem Computer)
ist lediglich eine Annahme, die manche Leute aus irgendwelchen Gruenden
machen moechten.
Auch die Summe wird ausweislich 6.5p5 mathematisch gebildet.
Post by Rainer Weikusat
Da eine so definierte Operation technisch nicht implementierbar ist,
kann man diese Interpretation als "offensichtlich unsinnig" verwerfen.
Nein, denn dem trägt ja 6.5p5 Rechnung.
Helmut Schellong
2018-09-21 10:37:08 UTC
Antworten
Permalink
Post by Rainer Weikusat
Die semantische Definition von + ist
Post by Helmut Schellong
lediglich
The result of the binary + operator is the sum of the operands.
Auch die Summe wird ausweislich 6.5p5 mathematisch gebildet.
Keinesfalls.
Dort steht, daß ein Resultat mathematisch undefiniert,
oder nicht repräsentierbar sein kann.

Ein mathematisch undefiniertes Resultat kann es bei
Addition gar nicht geben.

Das kommt dabei heraus, wenn man allgemein gehaltene
Absätze einfach total auf alles anwendet.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-21 22:33:42 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Rainer Weikusat
Die semantische Definition von + ist
Post by Helmut Schellong
lediglich
The result of the binary + operator is the sum of the operands.
Auch die Summe wird ausweislich 6.5p5 mathematisch gebildet.
Keinesfalls.
Dort steht, daß ein Resultat mathematisch undefiniert,
oder nicht repräsentierbar sein kann.
Ein mathematisch undefiniertes Resultat kann es bei
Addition gar nicht geben.
Na und? Das behauptet ja auch keiner. Einen im Typ nicht-darstellbaren
Wert dagegen durchaus.
Post by Helmut Schellong
Das kommt dabei heraus, wenn man allgemein gehaltene
Absätze einfach total auf alles anwendet.
Der besagte Absatz steht in der Einleitung zu "Expressions" und ist
auf jeden Teilabschnitt darin anzuwenden. Und zur Addition gibt es
keine speziellere entgegengesetzte Regel.
Helmut Schellong
2018-09-22 16:56:02 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Rainer Weikusat
Die semantische Definition von + ist
Post by Helmut Schellong
lediglich
The result of the binary + operator is the sum of the operands.
Auch die Summe wird ausweislich 6.5p5 mathematisch gebildet.
Keinesfalls.
Dort steht, daß ein Resultat mathematisch undefiniert,
oder nicht repräsentierbar sein kann.
Ein mathematisch undefiniertes Resultat kann es bei
Addition gar nicht geben.
Na und? Das behauptet ja auch keiner. Einen im Typ nicht-darstellbaren
Wert dagegen durchaus.
Es stimmt einfach nicht, daß ausweislich 6.5p5 die Summe
mathematisch gebildet wird.
Wie wird zwar mathematisch gebildet, jedoch nicht gemäß 6.5p5.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-23 23:40:39 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Rainer Weikusat
Die semantische Definition von + ist
Post by Helmut Schellong
lediglich
The result of the binary + operator is the sum of the operands.
Auch die Summe wird ausweislich 6.5p5 mathematisch gebildet.
Keinesfalls.
Dort steht, daß ein Resultat mathematisch undefiniert,
oder nicht repräsentierbar sein kann.
Ein mathematisch undefiniertes Resultat kann es bei
Addition gar nicht geben.
Na und? Das behauptet ja auch keiner. Einen im Typ nicht-darstellbaren
Wert dagegen durchaus.
Es stimmt einfach nicht, daß ausweislich 6.5p5 die Summe
mathematisch gebildet wird.
Wie wird zwar mathematisch gebildet, jedoch nicht gemäß 6.5p5.
Ach ja richtig. Man hat nur versäumt, die Addition als von 6.5p5
ausgenommen zu erklären. Oder wieso sonst soll auf einmal Teil 2 des
Satzes für Addition nicht gelten.

Dass ich diese fruchtlose Auseinandersetzung jetzt leid bin, heisst
definitiv nicht, dass ich Dir recht gebe!
Helmut Schellong
2018-09-24 11:50:00 UTC
Antworten
Permalink
[...]
Post by Ralf Damaschke
Post by Helmut Schellong
Es stimmt einfach nicht, daß ausweislich 6.5p5 die Summe
mathematisch gebildet wird.
Wie wird zwar mathematisch gebildet, jedoch nicht gemäß 6.5p5.
Ach ja richtig. Man hat nur versäumt, die Addition als von 6.5p5
ausgenommen zu erklären. Oder wieso sonst soll auf einmal Teil 2 des
Satzes für Addition nicht gelten.
Dass ich diese fruchtlose Auseinandersetzung jetzt leid bin, heisst
definitiv nicht, dass ich Dir recht gebe!
Die mathematische Summenbildung wird durch 6.5.6p5 Additive Operators
genannt.
Keinesfalls durch 6.5p5.

Dir wurde von anderer Seite 'ad ignorantiam' zugewiesen.
Ich kann das nachvollziehen, ob Deiner Argumentation.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Claus Reibenstein
2018-09-21 08:40:49 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Claus Reibenstein
LONG_MAX + 1 ist eine solche Ausnahmebedingung, weil das Ergebnis nicht
mehr als long darstellbar ist. Ergo: UB.
Das Leute das fuer aussergewoehnlich halten, heisst nicht, dass es das
auch ist.
Es geht nicht darum, was Leute für außergewöhnlich halten, sondern darum
was der Standard aussagt.
Post by Rainer Weikusat
Das kaeme auf die Hardware an
Der Standard ist unabhängig von irgendwelcher Hardware.
Post by Rainer Weikusat
Ein Ganzahlbereichsueberlauf *kann* als Fehler angesehen
werden. Oder als etwas anderes, zB koennte die Addition saettigend sein
oder auf einem Restklassenring definiert.
Du sagst es: Es kann alles Mögliche passieren. Genau das ist die
Definition von UB.
Post by Rainer Weikusat
Das hier eine Addition definiert auf der Menge der Zahlen gemeint ist
Auf was soll sie denn sonst definiert sein?

Gruß
Claus
Rainer Weikusat
2018-09-21 12:53:37 UTC
Antworten
Permalink
Post by Claus Reibenstein
Post by Rainer Weikusat
Post by Claus Reibenstein
LONG_MAX + 1 ist eine solche Ausnahmebedingung, weil das Ergebnis nicht
mehr als long darstellbar ist. Ergo: UB.
Das Leute das fuer aussergewoehnlich halten, heisst nicht, dass es das
auch ist.
Es geht nicht darum, was Leute für außergewöhnlich halten, sondern darum
was der Standard aussagt.
Genau.

[Addition]
Post by Claus Reibenstein
Post by Rainer Weikusat
Das kaeme auf die Hardware an
Der Standard ist unabhängig von irgendwelcher Hardware.
Deswegen spezifizert er dort auch kein Verhalten.
Post by Claus Reibenstein
Post by Rainer Weikusat
Ein Ganzahlbereichsueberlauf *kann* als Fehler angesehen
werden. Oder als etwas anderes, zB koennte die Addition saettigend sein
oder auf einem Restklassenring definiert.
Du sagst es: Es kann alles Mögliche passieren. Genau das ist die
Definition von UB.
Die Definition von 'undefiniertem Verhalten' ist 'es ist undefiniert',
dh wir wissen weiter nichts darueber. Und diesem Nichtwissen kann nicht
durch Spekulation ("alles moegliche") abgeholfen werden.
Post by Claus Reibenstein
Post by Rainer Weikusat
Das hier eine Addition definiert auf der Menge der Zahlen gemeint ist
Auf was soll sie denn sonst definiert sein?
Wie man dem Kontext haette entnehmen koennen, war die Menge, die der
Siebtklaessler als Z kennenlernt, gemeint. Es gibt auch noch andere
Mengen.
Ralf Damaschke
2018-09-21 22:50:43 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Ein Ganzahlbereichsueberlauf *kann* als Fehler angesehen
werden. Oder als etwas anderes, zB koennte die Addition saettigend sein
oder auf einem Restklassenring definiert.
Du sagst es: Es kann alles Mögliche passieren. Genau das ist die
Definition von UB.
Die Definition von 'undefiniertem Verhalten' ist 'es ist undefiniert',
dh wir wissen weiter nichts darueber.
Genau das ist die Aussage von "es kann alles Mögliche passieren".
Post by Rainer Weikusat
Und diesem Nichtwissen kann nicht
durch Spekulation ("alles moegliche") abgeholfen werden.
Spekulation wäre eher die Auskleidung mit Sättigung oder Restklassen.
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Das hier eine Addition definiert auf der Menge der Zahlen gemeint ist
Auf was soll sie denn sonst definiert sein?
Wie man dem Kontext haette entnehmen koennen, war die Menge, die der
Siebtklaessler als Z kennenlernt, gemeint. Es gibt auch noch andere
Mengen.
Ich verstehe nicht, was Du ausdrücken möchtest.
Helmut Schellong
2018-09-22 18:18:49 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Ein Ganzahlbereichsueberlauf *kann* als Fehler angesehen
werden. Oder als etwas anderes, zB koennte die Addition saettigend sein
oder auf einem Restklassenring definiert.
Du sagst es: Es kann alles Mögliche passieren. Genau das ist die
Definition von UB.
Die Definition von 'undefiniertem Verhalten' ist 'es ist undefiniert',
dh wir wissen weiter nichts darueber.
Genau das ist die Aussage von "es kann alles Mögliche passieren".
3.4.3 undefined behavior
behavior, upon use of a nonportable or erroneous program construct
or of erroneous data, for which this International Standard
imposes no requirements.

NOTE Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of
a diagnostic message).
EXAMPLE
An example of undefined behavior is the behavior on integer overflow.


Der letzte Satz ist bereits zutreffend, wenn nur einem Operator
bei Integer UB zugeordnet ist.
Eine Totschlagaussage kann eh nicht zugeordnet werden, da unsigned
Integer nicht getrennt betrachtet wird.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-23 23:44:44 UTC
Antworten
Permalink
Post by Helmut Schellong
3.4.3 undefined behavior
behavior, upon use of a nonportable or erroneous program construct
or of erroneous data, for which this International Standard
imposes no requirements.
NOTE Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of
a diagnostic message).
EXAMPLE
An example of undefined behavior is the behavior on integer overflow.
Der letzte Satz ist bereits zutreffend, wenn nur einem Operator
bei Integer UB zugeordnet ist.
Eine Totschlagaussage kann eh nicht zugeordnet werden, da unsigned
Integer nicht getrennt betrachtet wird.
Toll, jetzt hast Du Dir eine Strohpuppe gebastelt und eigenhändig
verbrannt.
Helmut Schellong
2018-09-24 11:57:01 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
3.4.3 undefined behavior
behavior, upon use of a nonportable or erroneous program construct
or of erroneous data, for which this International Standard
imposes no requirements.
NOTE Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of
a diagnostic message).
EXAMPLE
An example of undefined behavior is the behavior on integer overflow.
Der letzte Satz ist bereits zutreffend, wenn nur einem Operator
bei Integer UB zugeordnet ist.
Eine Totschlagaussage kann eh nicht zugeordnet werden, da unsigned
Integer nicht getrennt betrachtet wird.
Toll, jetzt hast Du Dir eine Strohpuppe gebastelt und eigenhändig
verbrannt.
Sehe ich nicht so.
Beispielsweise ist dem Divisions-Operator mehrfach UB zugewiesen.
Allein dadurch ist oben der 'letzte Satz' zutreffend.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2018-09-22 19:45:54 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Ein Ganzahlbereichsueberlauf *kann* als Fehler angesehen
werden. Oder als etwas anderes, zB koennte die Addition saettigend sein
oder auf einem Restklassenring definiert.
Du sagst es: Es kann alles Mögliche passieren. Genau das ist die
Definition von UB.
Die Definition von 'undefiniertem Verhalten' ist 'es ist undefiniert',
dh wir wissen weiter nichts darueber.
Genau das ist die Aussage von "es kann alles Mögliche passieren".
Es ist das Gegenteil dieser Ausage, naemlich "wir wissen nichts
darueber". Und dieses Nichtwissen laesst auf nichts schliessen. Der
Versuch ist ein klassischer Logikfehler, den man 'ad ignorantiam'
nennt. Eine solche Nichtfolgerung durch bedeutungslose Zusaetze wie
"moeglicherweise" scheinbar zu relativieren, aendert an der
Fehlerhaftigkeit des Gedankengangs nichts. Moeglicherweise faellt dann
ein US-Praesident tot um. Moeglicherweise aber auch nicht. Ergibt in Summe
"wir wissen es nicht" --- das wussten wir schon.
Post by Ralf Damaschke
Post by Rainer Weikusat
Und diesem Nichtwissen kann nicht durch Spekulation ("alles
moegliche") abgeholfen werden.
Spekulation wäre eher die Auskleidung mit Sättigung oder Restklassen.
Das sind real existierende Faelle, somit keine Spekulation.

[***@doppelsaurus]/tmp#cat a.c
#include <stdio.h>

int main(void)
{
signed char c;
c = 0;
do printf("%d\n", c); while (++c);
return 0;
}
[***@doppelsaurus]/tmp#gcc -fwrapv a.c
0
1
2
3
4
5

[...]

-6
-5
-4
-3
-2
-1
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Das hier eine Addition definiert auf der Menge der Zahlen gemeint ist
Auf was soll sie denn sonst definiert sein?
Wie man dem Kontext haette entnehmen koennen, war die Menge, die der
Siebtklaessler als Z kennenlernt, gemeint. Es gibt auch noch andere
Mengen.
Ich verstehe nicht, was Du ausdrücken möchtest.
Die Addition in obigem Programm ist auf einem Restklassenring definiert,
das ist dokumentiertes Verhalten. Ergo ergibt eine Addition nie einen
Wert, der nicht als char repraesentierbar waere.
Helmut Schellong
2018-09-22 22:20:27 UTC
Antworten
Permalink
[...]
Post by Rainer Weikusat
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Das hier eine Addition definiert auf der Menge der Zahlen gemeint ist
Auf was soll sie denn sonst definiert sein?
Wie man dem Kontext haette entnehmen koennen, war die Menge, die der
Siebtklaessler als Z kennenlernt, gemeint. Es gibt auch noch andere
Mengen.
Ich verstehe nicht, was Du ausdrücken möchtest.
Die Addition in obigem Programm ist auf einem Restklassenring definiert,
das ist dokumentiertes Verhalten. Ergo ergibt eine Addition nie einen
Wert, der nicht als char repraesentierbar waere.
Das erinnert mich an Interpretation und Spekulation.
Und an ein Gespräch, das ich vor Jahren mit anderen
Entwicklungsingenieuren führte über die Formulierungen
in Datenbüchern in Englisch, die von Japanern geschrieben
wurden.
Es wurde ein geringer Wortschatz verwendet.
Es wurden immer wieder die gleichen Formulierungen verwendet.
Es wurden simple Sätze mit vielen Wortwiederholungen gebildet.
Es wurde nicht auf 'schriftstellerische' Qualität geachtet.
Fazit:
Diese Datenbücher sind deshalb besonders gut verständlich!
Die Texte lassen keinen Raum für Spekulation und Interpretation!

Beim C-Standard fällt mir seit langem auf, daß sich die Autoren
einige Mühe geben, wohlformuliert variierend und mit einer
schriftstellerischen Qualität zu schreiben.
Das halte ich für falsch.
Am besten ist eine primitive Sprache mit kurzen Sätzen.

Ich habe gerade ein neues Kommando beschrieben.
Dabei habe ich bewußt 'schmucklos' primitiv formuliert.
Beispielsweise vermeide ich: "wie letzteres" zu formulieren,
sondern es wird artig immer wieder das gleiche Wort verwendet.
Und so weiter.

Fallbeispiel:
Die Beschreibung soll ein Spiegel des C-Codes sein:
=================================================================
run? [!] [Arg1] [Arg2] (-Z-)
Die Argumente Arg1 und Arg2 enthalten jeweils bish-Code.
Deren Inhalt wird in Abhängigkeit des aktuell
vorliegenden Exit-Codes ausgeführt:
Bei Exit = true wird der Inhalt des Arg1, und
bei Exit = false wird der Inhalt des Arg2
zur Ausführung gebracht.
Ist das erste Argument ein '!', wird der Exit-Code
invertiert bewertet.
Ein Argument wird evaluiert, wenn es existiert und der
Inhalt nicht leer ist.
Ein Argumentinhalt darf maximal 2040 Zeichen umfassen.
Dieses Kommando selbst setzt nicht den Exit-Code.
=================================================================
case RUNqm:
CstrP=0; opt=Exit;
if (C>0&&A[0][0]=='!'&&!A[0][1]) --C,++A, opt=!opt;
if (!opt) { if (C>0&&A[0][0]) CstrP=A[0]; }
else { if (C>1&&A[1][0]) CstrP=A[1]; }
if (CstrP) Input(0, ai+1, ap, ITYP_R, 0), CstrP=0;
break;
=================================================================
Ich schätze/hoffe, daß ich absolut keine Erklärungslücke
produziert habe, und keinen Raum für verschiedene Interpretationen.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Juergen Ilse
2018-09-22 23:10:30 UTC
Antworten
Permalink
Hallo,
Post by Helmut Schellong
Ich habe gerade ein neues Kommando beschrieben.
Dabei habe ich bewußt 'schmucklos' primitiv formuliert.
Beispielsweise vermeide ich: "wie letzteres" zu formulieren,
sondern es wird artig immer wieder das gleiche Wort verwendet.
Und so weiter.
=================================================================
run? [!] [Arg1] [Arg2] (-Z-)
Die Argumente Arg1 und Arg2 enthalten jeweils bish-Code.
Deren Inhalt wird in Abhängigkeit des aktuell
^^^^^^^^^^^^
Aha. "Es wird artig immer wieder das gleiche Wort verwendet". Warum
verwendest du dann hier einen solchen "Rueckbezug"? Warum "deren Inhalt"
und nicht "Der Inhalt der Argumente Arg1 und Arg2"?
Post by Helmut Schellong
Bei Exit = true wird der Inhalt des Arg1, und
bei Exit = false wird der Inhalt des Arg2
zur Ausführung gebracht.
Und wozu soll man dieses Ding ueberhaupt brauchen, wenn es das selbe
wie "if ... then ... else ..." tut? Weil es so schoen cryptischer ist?

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Helmut Schellong
2018-09-23 08:19:58 UTC
Antworten
Permalink
Post by Juergen Ilse
Hallo,
Post by Helmut Schellong
Ich habe gerade ein neues Kommando beschrieben.
Dabei habe ich bewußt 'schmucklos' primitiv formuliert.
Beispielsweise vermeide ich: "wie letzteres" zu formulieren,
sondern es wird artig immer wieder das gleiche Wort verwendet.
Und so weiter.
=================================================================
run? [!] [Arg1] [Arg2] (-Z-)
Die Argumente Arg1 und Arg2 enthalten jeweils bish-Code.
Deren Inhalt wird in Abhängigkeit des aktuell
^^^^^^^^^^^^
Aha. "Es wird artig immer wieder das gleiche Wort verwendet". Warum
verwendest du dann hier einen solchen "Rueckbezug"? Warum "deren Inhalt"
und nicht "Der Inhalt der Argumente Arg1 und Arg2"?
Der betreffende Satz lautet:
"Beispielsweise vermeide ich: "wie letzteres" zu formulieren,
sondern es wird artig immer wieder das gleiche Wort verwendet."

Ich habe dort "vermeide" und "wie letzteres" geschrieben.
Wenn eine Formulierung nichts 'vernebelt', gibt es keinen
Grund, sie nicht zu verwenden.
Im konkreten Fall sind nur drei Wörter dazwischen, in zwei
kurzen, direkt hintereinander stehenden Sätzen.
Man muß nichts übertreiben!
Post by Juergen Ilse
Post by Helmut Schellong
Bei Exit = true wird der Inhalt des Arg1, und
bei Exit = false wird der Inhalt des Arg2
zur Ausführung gebracht.
Und wozu soll man dieses Ding ueberhaupt brauchen, wenn es das selbe
wie "if ... then ... else ..." tut? Weil es so schoen cryptischer ist?
Ihr von der Newsgroup dcous seid wirklich ein bißchen 'krank' im Kopf.
Wenn etwas _Eigenes_ von POSIX abweicht, ist es 'kaputt' und ein Bug.
Daß es die eigene Spezifikation erfüllt, spielt keine Rolle, weil
diese eigene Spezifikation schon keine Rolle spielt.
Dabei werden in dcous zu sehr großen Teilen Abweichungen von POSIX
vieler sogenannter POSIX-Tools diskutiert. Beispielsweise statt
'make': gmake mmake smake pmake [a-z]make.

In der Dokumentation steht, warum dieses ergänzende 'run?'.
Und es ist überhaupt nicht kryptischer, sondern das Gegenteil.
"if ... then ... else ... fi" ist aufwendiger als
"run? arg arg" und ein Kommando einer anderen »Rubrik«:

# define CMD_Fu 1
# define CMD_SpecFu 2
# define CMD_SpecEFu 3
# define CMD_A0 4
# define CMD_A0E 5
# define CMD_CaseE 6
# define ABBR 7

In der gleichen Rubrik wie 'if ... fi' müßte 'run?'
so aussehen: 'run? ... alt ... end'.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-23 23:50:45 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Ralf Damaschke
Post by Rainer Weikusat
Die Definition von 'undefiniertem Verhalten' ist 'es ist undefiniert',
dh wir wissen weiter nichts darueber.
Genau das ist die Aussage von "es kann alles Mögliche passieren".
Es ist das Gegenteil dieser Ausage, naemlich "wir wissen nichts
darueber". Und dieses Nichtwissen laesst auf nichts schliessen. Der
Versuch ist ein klassischer Logikfehler, den man 'ad ignorantiam'
nennt. Eine solche Nichtfolgerung durch bedeutungslose Zusaetze wie
"moeglicherweise" scheinbar zu relativieren, aendert an der
Fehlerhaftigkeit des Gedankengangs nichts. Moeglicherweise faellt dann
ein US-Praesident tot um. Moeglicherweise aber auch nicht. Ergibt in Summe
"wir wissen es nicht" --- das wussten wir schon.
Post by Ralf Damaschke
Post by Rainer Weikusat
Und diesem Nichtwissen kann nicht durch Spekulation ("alles
moegliche") abgeholfen werden.
Das nennt aber eben nicht - wie von Dir behauptet - irgendeine
konkrete Möglichkeit (nicht einmal einen Hauch davon). Du hast eine
seltsame Einstellung zur Sprache. Für mich sind diese und Deine
Formulierung gleichwertig.
Post by Rainer Weikusat
Post by Ralf Damaschke
Spekulation wäre eher die Auskleidung mit Sättigung oder Restklassen.
Das sind real existierende Faelle, somit keine Spekulation.
Das macht sie aber nicht zu einer Definition, nur zu einer Auskleidung.
G. B.
2018-09-24 05:31:55 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Ralf Damaschke
Spekulation wäre eher die Auskleidung mit Sättigung oder Restklassen.
Das sind real existierende Faelle, somit keine Spekulation.
Das macht sie aber nicht zu einer Definition, nur zu einer Auskleidung.
Das Programm verhält sich. Damit wissen wir jetzt von einer Möglichkeit.
Und wir können spekulieren, ob dieses Verhalten nochmal vorkommen wird.
Juergen Ilse
2018-09-24 08:14:08 UTC
Antworten
Permalink
Hallo,
Post by G. B.
Post by Ralf Damaschke
Post by Rainer Weikusat
Post by Ralf Damaschke
Spekulation wäre eher die Auskleidung mit Sättigung oder Restklassen.
Das sind real existierende Faelle, somit keine Spekulation.
Das macht sie aber nicht zu einer Definition, nur zu einer Auskleidung.
Das Programm verhält sich. Damit wissen wir jetzt von einer Möglichkeit.
Und wir können spekulieren, ob dieses Verhalten nochmal vorkommen wird.
Vielleicht verhaelt es sich nur am 29.02. in Schaltjahren anders? Wir
wissen es schlicht nicht. Undefiniert heisst, dass wir noch nicht einmal
voraussetzen duerfen, dass es sich immer gleich verhaelt, noch nicht ein-
mal dann, wenn es sich bei 200000 Versuchen nie anders verhalten hat ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Helmut Schellong
2018-09-20 14:57:30 UTC
Antworten
Permalink
Post by Claus Reibenstein
Post by Helmut Schellong
Wo weist der Standard einer Addition (x+y) UB zu?
Ich habe hier leider nur den 99er, nicht den 89er. Im 99er steht in 6.5
Expressions Abschnitt 5 (und im 89er wird sicher Ähnliches, wenn nicht
"If an exceptional condition occurs during the evaluation of an
expression (that is, if the result is not mathematically defined or not
in the range of representable values for its type), the behavior is
undefined."
LONG_MAX + 1 ist eine solche Ausnahmebedingung, weil das Ergebnis nicht
mehr als long darstellbar ist. Ergo: UB.
Und nun kommst Du: Wo steht, dass dies ausgerechnet für die Addition
_nicht_ gelten soll?
Das habe ich bereits vor einer Reihe von Tagen beantwortet:

========================================================================
Post by Claus Reibenstein
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
erklärst Du für ungültig?:

6.2.6.2 Integer types
Absatz 2:
Which of these applies is implementation-defined, as is whether
the value with sign bit 1 and all value bits zero (for the first two),
or with sign bit and all value bits 1 (for ones¿ complement), is
a trap representation or a normal value.
In the case of sign and magnitude and ones¿ complement, if this
representation is a normal value it is called a negative zero.
Absatz 3:
It is unspecified whether these cases actually generate
a negative zero or a normal zero, and whether a negative zero
becomes a normal zero when stored in an object.
Absatz 4:
If the implementation does not support negative zeros, the behavior
of the &, |, ^, ~, <<, and >> operators with operands
that would produce such a value is undefined.

6.3.1.3 Signed and unsigned integers
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.

6.5.6 Additive operators
The result of the binary + operator is the sum of the operands.
The result of the binary - operator is the difference resulting
from the subtraction of the second operand from the first.

Es steht dort _nichts_ zu UB oder Traps oder Overflow oder
implem.-definiertem Verhalten!
Es folgt Pointer-Arithmetik.
========================================================================

Vorstehend schreibt der Standard unter 6.3.1.3 eindeutig, daß, wenn
ein Wert in signed Integer nicht repräsentiert werden kann, ein
implementations-definiertes Verhalten erfolgen muß.

Das ist aber _kein_ Widerspruch zu dem _allgemeinen_ Absatz
unter 6.5 Expressions.
Dieser Absatz nennt 'mathematisch undefiniert'.
Die Mathematik kennt keine Wertbegrenzung, aber beispielsweise
Division durch Null ist hier undefiniert.

Wenn ein Text weder Typ noch Operation nennt, können nicht einfach
automatisch sämtliche Typen und Operationen als betroffen angenommen
werden, falls an anderer Stelle _explizit_ Typen und/oder Operationen
als nicht betroffen herausgestellt werden.

Im Kapitel '6.3.1 Arithmetik operands' wird oftmals UB zugeordnet, wenn
der Wert nicht repräsentiert werden kann.
Beispielsweise in Verbindung mit Gleitkomma.
Bei Integer aber eben nicht, sondern explizit das Gegenteil.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Thomas Koenig
2018-09-20 17:22:00 UTC
Antworten
Permalink
Post by Helmut Schellong
========================================================================
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Einmal undefined behavior zu spezifizieren reicht.

Das muss nicht mehrere Male in der Norm stehen.
Helmut Schellong
2018-09-20 17:53:36 UTC
Antworten
Permalink
Post by Thomas Koenig
Post by Helmut Schellong
========================================================================
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Einmal undefined behavior zu spezifizieren reicht.
Das muss nicht mehrere Male in der Norm stehen.
Tut es aber.
Hier steht es, und z.B. bei multiplikativen Operatoren
zwei weitere Male.

Der Absatz oben nennt weder Typ noch Operation.
Es ist also notwendig, daß es woanders noch detaillierter
begründet und genau zugeordnet steht.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2018-09-20 18:51:37 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
========================================================================
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Einmal undefined behavior zu spezifizieren reicht.
Das muss nicht mehrere Male in der Norm stehen.
[...]
Post by Helmut Schellong
Der Absatz oben nennt weder Typ noch Operation.
Es ist also notwendig, daß es woanders noch detaillierter
begründet und genau zugeordnet steht.
Nicht unbedingt. Es genuegt, dass soetwas bei der Auswertung eines
Ausdrucks vorkommen kann. Ob es bei Additionen vorkommen kann, haengt
davon ab, wie eine Summe definiert ist. Die traditionalle C-Definition
ist "CPU-Addition". Die Definition der tradionellen
Mittelstufenmathematik bezieht sich auf die Menge der ganzen
Zahlen. Diverse, mathematisch etwas weitergehende andere Definitionen
existieren ebenfalls.

Falls sich die undefinierten eine aussuchen duerfen, die ihnen besonders
ab Herzen liegt, obwohl sie technischer Quatsch ist, dann duerfen alle
anderen das auch.
Ralf Damaschke
2018-09-20 23:59:35 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
========================================================================
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Einmal undefined behavior zu spezifizieren reicht.
Das muss nicht mehrere Male in der Norm stehen.
Tut es aber.
Hier steht es, und z.B. bei multiplikativen Operatoren
zwei weitere Male.
Der Absatz oben nennt weder Typ noch Operation.
Wozu auch?
Der Absatz gilt für alle Operationen bei der Berechnung von Ausdrücken.
Die Typen ergeben sich aus den Deklarationen der Variablen und den
Konstanten, die im Ausdruck verwendet werden, mittels der üblichen
arithmetischen Konvertierungen.
Post by Helmut Schellong
Es ist also notwendig, daß es woanders noch detaillierter
begründet und genau zugeordnet steht.
Nein, das leistet der Absatz bereits.

Im übrigen passt 6.3.1.3 schon deshalb nicht, weil sich 6.3 ausdrücklich
nur mit impliziten oder expliziten Konvertierungen befasst, und damit
nicht mit Berechnungen (d.h. bei signed char c = CHAR_MAX + 1) hättest
Du einen Punkt.
Helmut Schellong
2018-09-21 10:19:28 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Thomas Koenig
Post by Helmut Schellong
========================================================================
Post by Stefan Ram
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Und all die anderen relevanten Definitionen
Einmal undefined behavior zu spezifizieren reicht.
Das muss nicht mehrere Male in der Norm stehen.
Tut es aber.
Hier steht es, und z.B. bei multiplikativen Operatoren
zwei weitere Male.
Der Absatz oben nennt weder Typ noch Operation.
Wozu auch?
Der Absatz gilt für alle Operationen bei der Berechnung von Ausdrücken.
Die Typen ergeben sich aus den Deklarationen der Variablen und den
Konstanten, die im Ausdruck verwendet werden, mittels der üblichen
arithmetischen Konvertierungen.
Ja, allgemein gehaltene Absätze sind stets erlaubt.
Meistens sind solche einleitend.

These operators yield values that depend on the internal representations
of integers, and have implementation-defined and undefined aspects
for signed types.

Zum Beispiel der vorstehende Absatz.
Der wird an mehreren anderen Stellen noch ergänzt.
Post by Ralf Damaschke
Im übrigen passt 6.3.1.3 schon deshalb nicht, weil sich 6.3 ausdrücklich
nur mit impliziten oder expliziten Konvertierungen befasst, und damit
nicht mit Berechnungen (d.h. bei signed char c = CHAR_MAX + 1) hättest
Du einen Punkt.
6.5p5 beschreibt aber eine Situation, in der Konvertierungen jeder Art
beliebig vorkommen können.
Und Konvertierungen werden beispielsweise auch durch Addition vorgenommen.
Und an beiden Stellen wird explizit von Werten geschrieben, die nicht
repräsentiert werden können.

Ich kann mir eigentlich nicht vorstellen, daß, wenn Werte entstehen, die
nicht repräsentierbar sind, dieser Vorgang bei Konversionen
zu implementations-definiertem Verhalten führt, jedoch bei
Additionen stets UB resultiert.

Bei einem Addierwerk ist zudem undefiniertes Verhalten
gar nicht darstellbar.
Entweder werden Carry und Borrow berücksichtigt, oder eben nicht.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-21 22:30:14 UTC
Antworten
Permalink
[Abschnitt 6.5p5 in C11]
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Thomas Koenig
Einmal undefined behavior zu spezifizieren reicht.
Das muss nicht mehrere Male in der Norm stehen.
Tut es aber.
Hier steht es, und z.B. bei multiplikativen Operatoren
zwei weitere Male.
Der Absatz oben nennt weder Typ noch Operation.
Wozu auch?
Der Absatz gilt für alle Operationen bei der Berechnung von Ausdrücken.
Die Typen ergeben sich aus den Deklarationen der Variablen und den
Konstanten, die im Ausdruck verwendet werden, mittels der üblichen
arithmetischen Konvertierungen.
Ja, allgemein gehaltene Absätze sind stets erlaubt.
Meistens sind solche einleitend.
These operators yield values that depend on the internal representations
of integers, and have implementation-defined and undefined aspects
for signed types.
Zum Beispiel der vorstehende Absatz.
Der wird an mehreren anderen Stellen noch ergänzt.
Es ist doch nett, dass bei diesen Operationen, die inhärent von der
bitweisen Darstellung abhängen, explizit darauf hingewiesen wird.
Post by Helmut Schellong
Post by Ralf Damaschke
Im übrigen passt 6.3.1.3 schon deshalb nicht, weil sich 6.3 ausdrücklich
nur mit impliziten oder expliziten Konvertierungen befasst, und damit
nicht mit Berechnungen (d.h. bei signed char c = CHAR_MAX + 1) hättest
Du einen Punkt.
6.5p5 beschreibt aber eine Situation, in der Konvertierungen jeder Art
beliebig vorkommen können.
Und Konvertierungen werden beispielsweise auch durch Addition vorgenommen.
Und an beiden Stellen wird explizit von Werten geschrieben, die nicht
repräsentiert werden können.
Ich kann mir eigentlich nicht vorstellen, daß, wenn Werte entstehen, die
nicht repräsentierbar sind, dieser Vorgang bei Konversionen
zu implementations-definiertem Verhalten führt, jedoch bei
Additionen stets UB resultiert.
Vielleicht weil Du die Aspekte nicht ordentlich voneinander trennst.
Vor der Addition werden die 'usual arithmetic conversions' vorgenommen,
woraus sich ein 'common real type' für die Operanden und das Ergebnis
ergibt. Wenn das Additions-Ergebnis nicht in den gemeinsamen Typ passt,
bedeutet das UB (das erlaubt Dir auch, ein Addierwerk einfach tun zu
lassen, kann aber halt auch zu gänzlich anderen und undokumentierten
Folgen führen). Erst wenn das Additionsergebnis im gemeinsamen Typ
vorliegt, kann der Wert in ein Objekt eines bestimmten Zieltyps
übertragen werden. Dann erst greift 6.3.1.3 (sofern nicht zuvor UB
hervorgerufen wurde) bei der Konvertierung und fordert ggf. ein
von der Implementierung definiertes Resultat bzw. Trap.
Post by Helmut Schellong
Bei einem Addierwerk ist zudem undefiniertes Verhalten
gar nicht darstellbar.
Entweder werden Carry und Borrow berücksichtigt, oder eben nicht.
Natürlich lässt sich mit einem Addierwerk ein bestimmtes (auch ein
vom Standard nicht definiertes) Verhalten darstellen.
Bloß blöd, dass die C-Norm kein Addierwerk vorgibt. Das darfst Du
einsetzen, um bestimmtes Verhalten einer bestimmten Implementierung
nachzuvollziehen, aber nicht als Teil des Regelwerks betrachten.
Helmut Schellong
2018-09-22 18:05:15 UTC
Antworten
Permalink
[...]
Post by Ralf Damaschke
Post by Helmut Schellong
Ich kann mir eigentlich nicht vorstellen, daß, wenn Werte entstehen, die
nicht repräsentierbar sind, dieser Vorgang bei Konversionen
zu implementations-definiertem Verhalten führt, jedoch bei
Additionen stets UB resultiert.
Vielleicht weil Du die Aspekte nicht ordentlich voneinander trennst.
Vor der Addition werden die 'usual arithmetic conversions' vorgenommen,
woraus sich ein 'common real type' für die Operanden und das Ergebnis
ergibt. Wenn das Additions-Ergebnis nicht in den gemeinsamen Typ passt,
bedeutet das UB (das erlaubt Dir auch, ein Addierwerk einfach tun zu
lassen, kann aber halt auch zu gänzlich anderen und undokumentierten
Folgen führen). Erst wenn das Additionsergebnis im gemeinsamen Typ
vorliegt, kann der Wert in ein Objekt eines bestimmten Zieltyps
übertragen werden. Dann erst greift 6.3.1.3 (sofern nicht zuvor UB
hervorgerufen wurde) bei der Konvertierung und fordert ggf. ein
von der Implementierung definiertes Resultat bzw. Trap.
Du legst Dir doch eine Reihenfolge und Bewertung zurecht, so daß
Deine Meinung paßt.
UB von 6.5 her hat also Vorrang vor den Definitionen in 6.3. ...

----------------------------------------------------------------------
6.5p5 If an exceptional condition occurs during the evaluation of
an expression (that is, if the result is not mathematically defined
or not in the range of representable values for its type), the
behavior is undefined.
----------------------------------------------------------------------

Ich bin bei solchen sehr allgemein gehaltenen Texten stets vorsichtig!
Das schrieb ich schon vor Tagen.
Der Text lautet übersetzt:
»Wenn ein Ausnahmezustand auftritt, während der Auswertung eines
Ausdrucks, ist das Verhalten undefiniert.«

Das bedeutet, es ist egal, _wodurch_ die Ausnahme auftritt.
Demnach gibt es auch durch die Entstehung von nicht repräsentierbaren
Werten bei Konversionen und signed Integer UB, was allerdings
durch einen anderen Paragraphen _zuvor_ ausgeschlossen ist.

Im Absatz steht auch nicht: daß er generell gilt, sofern an
anderer Stelle nichts Abweichendes festgelegt ist.

Danach werden die Operatoren einzeln beschrieben.
Die Operatoren * / + - << können Überlauf erzeugen.
Bei allen diesen wird UB zugeordnet - mit Ausnahme bei '+ -'.
Warum diese Ausnahme und 6.3.1.3 bezüglich '+ -'?

Für mich ist das Überlaufverhalten bei '+ -' daher schlicht
implementations-definiert.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-23 23:33:17 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Vielleicht weil Du die Aspekte nicht ordentlich voneinander trennst.
Vor der Addition werden die 'usual arithmetic conversions' vorgenommen,
woraus sich ein 'common real type' für die Operanden und das Ergebnis
ergibt. Wenn das Additions-Ergebnis nicht in den gemeinsamen Typ passt,
bedeutet das UB (das erlaubt Dir auch, ein Addierwerk einfach tun zu
lassen, kann aber halt auch zu gänzlich anderen und undokumentierten
Folgen führen). Erst wenn das Additionsergebnis im gemeinsamen Typ
vorliegt, kann der Wert in ein Objekt eines bestimmten Zieltyps
übertragen werden. Dann erst greift 6.3.1.3 (sofern nicht zuvor UB
hervorgerufen wurde) bei der Konvertierung und fordert ggf. ein
von der Implementierung definiertes Resultat bzw. Trap.
Du legst Dir doch eine Reihenfolge und Bewertung zurecht, so daß
Deine Meinung paßt.
UB von 6.5 her hat also Vorrang vor den Definitionen in 6.3. ...
Während Du nicht einmal den Versuch machst /usual arithmetic
conversions/ und /common real type/ zu erfassen (übrigens beides
6.3.1.8).

Na dann erklär mal mit Deiner Ansicht, wieso (bei INT_MAX < LONG_MAX)
das Ergebnis von "int i = INT_MAX; long lv = i + i" von 2*INT_MAX
verschieden ist. Bei der Konvertierung von int nach long kann ja wohl
unbestritten kein Überlauf auftreten, also 6.3.1.3 nicht über p3 laufen.
Post by Helmut Schellong
----------------------------------------------------------------------
6.5p5 If an exceptional condition occurs during the evaluation of
an expression (that is, if the result is not mathematically defined
or not in the range of representable values for its type), the
behavior is undefined.
----------------------------------------------------------------------
Ich bin bei solchen sehr allgemein gehaltenen Texten stets vorsichtig!
Das schrieb ich schon vor Tagen.
»Wenn ein Ausnahmezustand auftritt, während der Auswertung eines
Ausdrucks, ist das Verhalten undefiniert.«
Nur, wenn man die Konkretisierung nicht wahrnehmen will.
Post by Helmut Schellong
Das bedeutet, es ist egal, _wodurch_ die Ausnahme auftritt.
Demnach gibt es auch durch die Entstehung von nicht repräsentierbaren
Werten bei Konversionen und signed Integer UB, was allerdings
durch einen anderen Paragraphen _zuvor_ ausgeschlossen ist.
Nein, weil das Ergebnis im /common real type/ berechnet wird, also
durch die Addition selbst keine Konvertierung vorgenommen wird.
Post by Helmut Schellong
Im Absatz steht auch nicht: daß er generell gilt, sofern an
anderer Stelle nichts Abweichendes festgelegt ist.
Danach werden die Operatoren einzeln beschrieben.
Die Operatoren * / + - << können Überlauf erzeugen.
Bei allen diesen wird UB zugeordnet - mit Ausnahme bei '+ -'.
Warum diese Ausnahme und 6.3.1.3 bezüglich '+ -'?
Für mich ist das Überlaufverhalten bei '+ -' daher schlicht
implementations-definiert.
Deine Meinung ist aber durch den Standard nicht gedeckt.
Helmut Schellong
2018-09-24 11:37:24 UTC
Antworten
Permalink
[...]
Post by Ralf Damaschke
Post by Helmut Schellong
Du legst Dir doch eine Reihenfolge und Bewertung zurecht, so daß
Deine Meinung paßt.
UB von 6.5 her hat also Vorrang vor den Definitionen in 6.3. ...
Während Du nicht einmal den Versuch machst /usual arithmetic
conversions/ und /common real type/ zu erfassen (übrigens beides
6.3.1.8).
Die hatte ich bereits in den 1980ern Jahren erfaßt.
Und 2005 in mein erstes C-Buch geschrieben.
Post by Ralf Damaschke
Na dann erklär mal mit Deiner Ansicht, wieso (bei INT_MAX < LONG_MAX)
das Ergebnis von "int i = INT_MAX; long lv = i + i" von 2*INT_MAX
verschieden ist. Bei der Konvertierung von int nach long kann ja wohl
unbestritten kein Überlauf auftreten, also 6.3.1.3 nicht über p3 laufen.
Das Ergebnis ist hier unbestritten unterschiedlich.
Ich sehe es jedoch nicht, daß bei Addition UB auftreten soll.
Post by Ralf Damaschke
Post by Helmut Schellong
----------------------------------------------------------------------
6.5p5 If an exceptional condition occurs during the evaluation of
an expression (that is, if the result is not mathematically defined
or not in the range of representable values for its type), the
behavior is undefined.
----------------------------------------------------------------------
Ich bin bei solchen sehr allgemein gehaltenen Texten stets vorsichtig!
Das schrieb ich schon vor Tagen.
»Wenn ein Ausnahmezustand auftritt, während der Auswertung eines
Ausdrucks, ist das Verhalten undefiniert.«
Nur, wenn man die Konkretisierung nicht wahrnehmen will.
Welche Konkretisierung?
Der Satz sagt das aus, was man lesen kann.
Die Definition des 'Ausnahmezustand' könnte auch ganz
woanders stehen.
Der Satz sagt nicht aus, daß Ausnahmezustände, die durch
Konversion entstehen, ausgeschlossen sind.
Post by Ralf Damaschke
Post by Helmut Schellong
Das bedeutet, es ist egal, _wodurch_ die Ausnahme auftritt.
Demnach gibt es auch durch die Entstehung von nicht repräsentierbaren
Werten bei Konversionen und signed Integer UB, was allerdings
durch einen anderen Paragraphen _zuvor_ ausgeschlossen ist.
Nein, weil das Ergebnis im /common real type/ berechnet wird, also
durch die Addition selbst keine Konvertierung vorgenommen wird.
Nichts davon sagt der Absatz aus.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Ram
2018-09-20 15:05:27 UTC
Antworten
Permalink
Post by Ralf Damaschke
Doch es ist falsch (6.5p5). LONG_MAX+1 lässt sich nicht in einem
long darstellen.
Wer bei INT_MAX+1 kein UB sieht, soll mal das Verhalten von gcc
(wohl ab gcc6, ohne Optionen wie »-ftrapv« oder Ähnliches, also
»gcc main.c«) für das folgende Programm erklären!

main.c

#include <stdio.h>
#include <limits.h>

int main()
{ int n = INT_MAX;
printf( "%d, %d\n", n + 1 > n, INT_MAX + 1 > INT_MAX ); }

transcript

1, 0

Diese C-Implementation verhält sich normgerecht.
Stefan Ram
2018-09-20 15:14:08 UTC
Antworten
Permalink
Post by Stefan Ram
wohl ab gcc6
PS: Hier getestet mit

$ gcc --version
gcc (GCC) 8.1.0

.
Rainer Weikusat
2018-09-20 16:28:30 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Ralf Damaschke
Doch es ist falsch (6.5p5). LONG_MAX+1 lässt sich nicht in einem
long darstellen.
Wer bei INT_MAX+1 kein UB sieht, soll mal das Verhalten von gcc
(wohl ab gcc6, ohne Optionen wie »-ftrapv« oder Ähnliches, also
»gcc main.c«) für das folgende Programm erklären!
main.c
#include <stdio.h>
#include <limits.h>
int main()
{ int n = INT_MAX;
printf( "%d, %d\n", n + 1 > n, INT_MAX + 1 > INT_MAX ); }
transcript
1, 0
Diese C-Implementation verhält sich normgerecht.
Das erklaert sich so, dass die verantwortlichen Entwickler auch eine
Meinung zum Thema "Bereichsueberschreitung bei Ganzahlarithmetik" haben,
die sie mangels Hardware in einen Compiler kodiert haben, lediglich ein
bisschen schludrig:
Thomas Koenig
2018-09-20 17:24:26 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Ralf Damaschke
Doch es ist falsch (6.5p5). LONG_MAX+1 lässt sich nicht in einem
long darstellen.
Wer bei INT_MAX+1 kein UB sieht, soll mal das Verhalten von gcc
(wohl ab gcc6, ohne Optionen wie »-ftrapv« oder Ähnliches, also
»gcc main.c«) für das folgende Programm erklären!
main.c
#include <stdio.h>
#include <limits.h>
int main()
{ int n = INT_MAX;
printf( "%d, %d\n", n + 1 > n, INT_MAX + 1 > INT_MAX ); }
Bei mir:

$ gcc a.c
a.c: In function 'main':
a.c:6:42: warning: integer overflow in expression of type 'int' results
in '-2147483648' [-Woverflow]
6 | printf( "%d, %d\n", n + 1 > n, INT_MAX + 1 > INT_MAX );

Das ist mit

gcc version 9.0.0 20180919 (experimental) (GCC)
Helmut Schellong
2018-09-20 17:45:28 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Ralf Damaschke
Doch es ist falsch (6.5p5). LONG_MAX+1 lässt sich nicht in einem
long darstellen.
Wer bei INT_MAX+1 kein UB sieht, soll mal das Verhalten von gcc
(wohl ab gcc6, ohne Optionen wie »-ftrapv« oder Ähnliches, also
»gcc main.c«) für das folgende Programm erklären!
main.c
#include <stdio.h>
#include <limits.h>
int main()
{ int n = INT_MAX;
printf( "%d, %d\n", n + 1 > n, INT_MAX + 1 > INT_MAX ); }
Das ist völlig normal und kein Problem.
Ich schrieb das vor 5 Tagen:

1# echo $((~0))
-1
2# echo $((~0+1))
0
3# echo $((~0+2))
1
4# echo $((~0>>1))
9223372036854775807
5# echo $(([~0>>1]+1))
-9223372036854775808
6# echo $(([~0>>1]+2))
-9223372036854775807
7# echo $(([~0>>1]-1))
9223372036854775806
8#

Wenn man das anhand von 8 Bit 2er-Komplement betrachtet:
max = 01111111 = 127
max+1 = 10000000 = -128
11111111 = -1
1 + 11111111 = 0
Hier gibt es keine zwei Bitrepräsentationen für einen Wert.
Subtrahiert wird durch Addition einer negierten Zahl.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Helmut Schellong
2018-09-16 20:10:23 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Bastian Blank
Wenn du dir da so sicher bist kannst du doch bestimmt den aktuellen
C-Standard zitieren.
|5 If an exceptional condition occurs during the evaluation of
|an expression (that is, if the result is not mathematically
|defined or not in the range of representable values for its
|type), the behavior is undefined.
Dies spricht erst einmal dafür, daß INT_MAX+1 UB hat, wenn
niemand eine spezielle Ausnahmeregel für INT_MAX+1 findet.
Nein, dieser Text bezieht sich auf sämtliche in einem
Ausdruck verwendbaren Operatoren;
und für viele davon definiert der Standard UB, beispielsweise
für Division durch Null.

Hier geht es aber _nur_ um den Operator '+', für den der
Standard nirgendwo mögliches UB definiert!
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-15 17:07:10 UTC
Antworten
Permalink
Post by Thomas Koenig
Ein Programm soll eine Ganzzahl von standard input einlesen lesen,
um eins erhöhen und auf standard output ausgeben. Für den Fall,
dass dies nicht möglich ist, soll ein Fehlschlag an die Umgebung
signalisiert werden, ansonsten Erfolg. Das Programm soll der
C89-Norm entsprechen.
Lösungsansatz: Das folgende Progrämmchen.
#include <stdio.h>
#include <stdlib.h>
int main()
{
long i;
if (scanf("%ld", &i) != 1)
exit (EXIT_FAILURE);
i++;
printf("%ld\n", i);
exit (EXIT_SUCCESS);
}
Problem: Bei Ausführung des Programmes kann undefined
behavior auftreten.
Wie käme man da drum rum?
Der mögliche signed-Überlauf beim Inkrementieren wurde ja schon
angesprochen. Doch auch beim Einlesen kann zu es Überlauf mit
Folge "undefined behavior" kommen. Abhilfe im einfachen Fall wie
hier wäre Einlesen der ganzen Zeile (im weniger einfachen Fall
nur des Teils, der einer Ziffernfolge ggf. mit Vorzeichen
entspricht) nebst Konvertierung mittels strtol.
Helmut Schellong
2018-09-15 17:45:23 UTC
Antworten
Permalink
Post by Ralf Damaschke
Der mögliche signed-Überlauf beim Inkrementieren wurde ja schon
angesprochen. Doch auch beim Einlesen kann zu es Überlauf mit
Folge "undefined behavior" kommen.
Der Standard schreibt, daß bei Argumenten, die nicht zum
Format passen, UB bewirkt wird.
'Überlauf' als Grund nennt der Standard dort nicht.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-16 18:24:09 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Der mögliche signed-Überlauf beim Inkrementieren wurde ja schon
angesprochen. Doch auch beim Einlesen kann zu es Überlauf mit
Folge "undefined behavior" kommen.
Der Standard schreibt, daß bei Argumenten, die nicht zum
Format passen, UB bewirkt wird.
'Überlauf' als Grund nennt der Standard dort nicht.
Das steht aber sehr deutlich sehr anders ebenda bei der fscanf Funktion:

| If this object does not have an appropriate type, or if the result of
| the conversion cannot be represented in the object, the behavior is
| undefined.

Ich hoffe, Du willst nicht debattieren, ob der Versuch einen zu
großen Wert zuzuweisen, als Überlauf bezeichnet werden kann.
Helmut Schellong
2018-09-16 19:23:42 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Ralf Damaschke
Der mögliche signed-Überlauf beim Inkrementieren wurde ja schon
angesprochen. Doch auch beim Einlesen kann zu es Überlauf mit
Folge "undefined behavior" kommen.
Der Standard schreibt, daß bei Argumenten, die nicht zum
Format passen, UB bewirkt wird.
'Überlauf' als Grund nennt der Standard dort nicht.
| If this object does not have an appropriate type, or if the result of
| the conversion cannot be represented in the object, the behavior is
| undefined.
Ich hoffe, Du willst nicht debattieren, ob der Versuch einen zu
großen Wert zuzuweisen, als Überlauf bezeichnet werden kann.
Absatz 2 von mir bereits gepostet worden:

fscanf Absatz 2:
If there are insufficient arguments for the format, the
behavior is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.

fscanf Absatz 10:
Unless assignment suppression was indicated by a *, the result
of the conversion is placed in the object pointed to by the
first argument following the format argument that has not already
received a conversion result. If this object does not have
an appropriate type, or if the result of the conversion cannot
be represented in the object, the behavior is undefined.

Diese Definitionen gelten nur für die (f)scanf-Funktionen!

Allgemein für signed Integer:
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.

Vorstehendes und Weiteres hatte ich ebenfalls bereits gepostet.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-17 00:58:03 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Ralf Damaschke
Der mögliche signed-Überlauf beim Inkrementieren wurde ja schon
angesprochen. Doch auch beim Einlesen kann zu es Überlauf mit
Folge "undefined behavior" kommen.
Der Standard schreibt, daß bei Argumenten, die nicht zum
Format passen, UB bewirkt wird.
'Überlauf' als Grund nennt der Standard dort nicht.
| If this object does not have an appropriate type, or if the result of
| the conversion cannot be represented in the object, the behavior is
| undefined.
If there are insufficient arguments for the format, the
behavior is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.
Das ist irrelevant für den diskutierten Fall 'scanf("%ld", &i)'. Der
Absatz wäre nicht einmal einschlägig, wenn i einen unpassenden Typ
hätte.
Post by Helmut Schellong
Unless assignment suppression was indicated by a *, the result
of the conversion is placed in the object pointed to by the
first argument following the format argument that has not already
received a conversion result. If this object does not have
an appropriate type, or if the result of the conversion cannot
be represented in the object, the behavior is undefined.
Diese Definitionen gelten nur für die (f)scanf-Funktionen!
Ja, genau (abgesehen vom unpassenden Begriff 'Definitionen'),
deshalb habe ich ja daraus zitiert:
Wenn '271828182845904523536' größer ist als LONG_MAX, dann führt
der Versuch diese Zahl mit 'long i; scanf("%ld", &i)' einzulesen,
zu undefiniertem Verhalten.
Post by Helmut Schellong
Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.
Vorstehendes und Weiteres hatte ich ebenfalls bereits gepostet.
Das bezieht sich auf Wert-Zuweisungen und verliert allemal gegen
die engere Bestimmung durch den fscanf-Absatz.
Helmut Schellong
2018-09-17 10:46:27 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
If there are insufficient arguments for the format, the
behavior is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.
Das ist irrelevant für den diskutierten Fall 'scanf("%ld", &i)'. Der
Absatz wäre nicht einmal einschlägig, wenn i einen unpassenden Typ
hätte.
Das ist nicht irrelevant!
Weder Absatz 2, noch Absatz 10 diskutieren speziell den Fall
'scanf("%ld", &i)', sie diskutieren gar keinen speziellen Fall.

=================================================================
7.21.6.2 The fscanf function
S y n o p s i s
Absatz 1:
#include <stdio.h>
int fscanf(FILE * restrict stream,
const char * restrict format, ...);
D e s c r i p t i o n
Absatz 2:
The fscanf function reads input from the stream pointed to
by stream, under control of the string pointed to by format
that specifies the admissible input sequences and how they are
to be converted for assignment, using subsequent arguments
as pointers to the objects to receive the converted input.
If there are insufficient arguments for the format, the behavior
is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.
=================================================================

Der vorstehende Absatz ist ein General-Absatz, der für jegliche
Format-Sequenz gilt.
Dieser einleitende Absatz 2 gilt bis Absatz 27 einschließlich,
widerspruchslos.

Absatz 10 handelt ebenfalls nicht von bestimmten Format-Sequenzen,
sondern beschreibt die Operationen von fprintf() detaillierter,
widerspricht aber in keiner Weise Absatz 2.
Post by Ralf Damaschke
Post by Helmut Schellong
Unless assignment suppression was indicated by a *, the result
of the conversion is placed in the object pointed to by the
first argument following the format argument that has not already
received a conversion result. If this object does not have
an appropriate type, or if the result of the conversion cannot
be represented in the object, the behavior is undefined.
Diese Definitionen gelten nur für die (f)scanf-Funktionen!
Ja, genau (abgesehen vom unpassenden Begriff 'Definitionen'),
Der Standard definiert hier die Operationen, die eine Funktion
fscanf vornehmen soll - wie sie implementiert werden soll.
Post by Ralf Damaschke
Wenn '271828182845904523536' größer ist als LONG_MAX, dann führt
der Versuch diese Zahl mit 'long i; scanf("%ld", &i)' einzulesen,
zu undefiniertem Verhalten.
Ja.
Nur Absatz 10 hebt in keiner Weise auf diesen speziellen Fall ab.
Absatz 2 beschreibt das ebenfalls schon zuvor.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-17 18:12:30 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
If there are insufficient arguments for the format, the
behavior is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.
Das ist irrelevant für den diskutierten Fall 'scanf("%ld", &i)'. Der
Absatz wäre nicht einmal einschlägig, wenn i einen unpassenden Typ
hätte.
Das ist nicht irrelevant!
Weder Absatz 2, noch Absatz 10 diskutieren speziell den Fall
'scanf("%ld", &i)', sie diskutieren gar keinen speziellen Fall.
Blödsinn. Absatz 10 beschreibt die Konvertierung an das Zielobjekt,
wie sie auch bei 'scanf("%ld", &i)' auftritt.
Absatz 2 beschreibt das Verhalten bei zu wenigen 'scanf("%ld")' oder
zu vielen 'scanf(".", &i)' Argumenten.
Post by Helmut Schellong
Absatz 10 handelt ebenfalls nicht von bestimmten Format-Sequenzen,
sondern beschreibt die Operationen von fprintf() detaillierter,
widerspricht aber in keiner Weise Absatz 2.
Natürlich nicht. Sie ergänzen sich. Allerdings liegt hier keiner der
in Absatz 2 angesprochenen Fälle nicht vor.
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Unless assignment suppression was indicated by a *, the result
of the conversion is placed in the object pointed to by the
first argument following the format argument that has not already
received a conversion result. If this object does not have
an appropriate type, or if the result of the conversion cannot
be represented in the object, the behavior is undefined.
Diese Definitionen gelten nur für die (f)scanf-Funktionen!
Wenn '271828182845904523536' größer ist als LONG_MAX, dann führt
der Versuch diese Zahl mit 'long i; scanf("%ld", &i)' einzulesen,
zu undefiniertem Verhalten.
Ja.
Nur Absatz 10 hebt in keiner Weise auf diesen speziellen Fall ab.
Absatz 2 beschreibt das ebenfalls schon zuvor.
Ad 10: Doch; der Wert kann nicht im Zielobjekt dargestellt werden.
Ad 2: Nein; Format und Anzahl der Argumente passen zueinander.
Helmut Schellong
2018-09-17 21:43:09 UTC
Antworten
Permalink
Post by Ralf Damaschke
Post by Helmut Schellong
Das ist nicht irrelevant!
Weder Absatz 2, noch Absatz 10 diskutieren speziell den Fall
'scanf("%ld", &i)', sie diskutieren gar keinen speziellen Fall.
Blödsinn. Absatz 10 beschreibt die Konvertierung an das Zielobjekt,
wie sie auch bei 'scanf("%ld", &i)' auftritt.
Weder Absatz 2, noch Absatz 10 diskutieren speziell den Fall
'scanf("%ld", &i)'.
Sie beschreiben allgemein, ohne irgendeinen Fall herauszuheben.
Und für Dich ist es Blödsinn, diese Tatsache zu benennen.
Post by Ralf Damaschke
Absatz 2 beschreibt das Verhalten bei zu wenigen 'scanf("%ld")' oder
zu vielen 'scanf(".", &i)' Argumenten.
Absatz 2 beschreibt ebenfalls das Verhalten, wenn Format
und Argumente nicht zueinander passen.
Dabei kommt es auch oft vor, daß Werte nicht repräsentiert
werden können.
Unpassende Eingaben werden in diesem Absatz 2 allerdings
nicht behandelt.
Es ist nicht klar, ob zu große Zahlen in der Eingabe
eine 'matching sequence' sind oder nicht.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-18 22:13:25 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Das ist nicht irrelevant!
Weder Absatz 2, noch Absatz 10 diskutieren speziell den Fall
'scanf("%ld", &i)', sie diskutieren gar keinen speziellen Fall.
Blödsinn. Absatz 10 beschreibt die Konvertierung an das Zielobjekt,
wie sie auch bei 'scanf("%ld", &i)' auftritt.
Weder Absatz 2, noch Absatz 10 diskutieren speziell den Fall
'scanf("%ld", &i)'.
Sie beschreiben allgemein, ohne irgendeinen Fall herauszuheben.
Und für Dich ist es Blödsinn, diese Tatsache zu benennen.
Das schrieb ich so nicht! Natürlich wird nicht jeder spezielle
Aufruf behandelt, aber Absatz nur 10 beschreibt Probleme, die bei der
Konvertierung bei einem ansonsten korrekten Aufruf auftreten können.
Post by Helmut Schellong
Post by Ralf Damaschke
Absatz 2 beschreibt das Verhalten bei zu wenigen 'scanf("%ld")' oder
zu vielen 'scanf(".", &i)' Argumenten.
Absatz 2 beschreibt ebenfalls das Verhalten, wenn Format
und Argumente nicht zueinander passen.
Nur in Bezug auf Diskrepanzen zwischen Format und Anzahl der
Argumente: "insufficient" = nicht genügend viele, oder eben
"excess" = überschüssige. Im Gegensatz zu Absatz 10: "object does
not have an appropriate type" = zum Format upassender Objekttyp bzw.
"result [...] cannot be represented in the object" = aktueller Wert
passt nicht (z.B. zu groß oder zu lang).
Post by Helmut Schellong
Dabei kommt es auch oft vor, daß Werte nicht repräsentiert
werden können.
Unpassende Eingaben werden in diesem Absatz 2 allerdings
nicht behandelt.
Natürlich nicht, dafür ist dieser Absatz auch nicht gedacht.
Post by Helmut Schellong
Es ist nicht klar, ob zu große Zahlen in der Eingabe
eine 'matching sequence' sind oder nicht.
Doch, das wird exakt bei der Beschreibung der fscanf-Konvertierung
"%d" vorgegeben.
Helmut Schellong
2018-09-19 17:10:17 UTC
Antworten
Permalink
[...]
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Ralf Damaschke
Absatz 2 beschreibt das Verhalten bei zu wenigen 'scanf("%ld")' oder
zu vielen 'scanf(".", &i)' Argumenten.
Absatz 2 beschreibt ebenfalls das Verhalten, wenn Format
und Argumente nicht zueinander passen.
Nur in Bezug auf Diskrepanzen zwischen Format und Anzahl der
Argumente: "insufficient" = nicht genügend viele, oder eben
"excess" = überschüssige.
insufficient = unzulänglich, mangelhaft, ungenügend, ...

-----------------------------------------------------------------
If there are insufficient arguments for the format, the behavior
is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.
-----------------------------------------------------------------

Der zweite Satz ist klar:
Er nennt übrig bleibende und überzählige Argumente, und
bezieht sich damit eindeutig auf die Anzahl der Argumente.

Wenn ich mal direkt übersetze:
"Falls da sind unzulängliche Argumente für das Format"
Dann ist die Aussage zum ersten Satz arg zweifelhaft.

Ich interpretiere daraus, daß es um Argumente geht, die nicht
zu ihrer Formatsequenz passen.

Beispiel: "%lf", int
Post by Ralf Damaschke
Post by Helmut Schellong
Dabei kommt es auch oft vor, daß Werte nicht repräsentiert
werden können.
Unpassende Eingaben werden in diesem Absatz 2 allerdings
nicht behandelt.
Natürlich nicht, dafür ist dieser Absatz auch nicht gedacht.
Post by Helmut Schellong
Es ist nicht klar, ob zu große Zahlen in der Eingabe
eine 'matching sequence' sind oder nicht.
Doch, das wird exakt bei der Beschreibung der fscanf-Konvertierung
"%d" vorgegeben.
Ich meinte, ob sie matchen, oder nicht und daher weggeworfen werden.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2018-09-19 17:23:08 UTC
Antworten
Permalink
Post by Helmut Schellong
[...]
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Ralf Damaschke
Absatz 2 beschreibt das Verhalten bei zu wenigen 'scanf("%ld")' oder
zu vielen 'scanf(".", &i)' Argumenten.
Absatz 2 beschreibt ebenfalls das Verhalten, wenn Format
und Argumente nicht zueinander passen.
Nur in Bezug auf Diskrepanzen zwischen Format und Anzahl der
Argumente: "insufficient" = nicht genügend viele, oder eben
"excess" = überschüssige.
insufficient = unzulänglich, mangelhaft, ungenügend, ...
-----------------------------------------------------------------
If there are insufficient arguments for the format, the behavior
is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.
-----------------------------------------------------------------
Er nennt übrig bleibende und überzählige Argumente, und
bezieht sich damit eindeutig auf die Anzahl der Argumente.
"Falls da sind unzulängliche Argumente für das Format"
Dann ist die Aussage zum ersten Satz arg zweifelhaft.
Auf Deutsch heisst das "Wenn nicht genueged Argumente fuer das Format
vorhanden sind, ist das Verhalten undefiniert".
Rainer Weikusat
2018-09-19 17:29:25 UTC
Antworten
Permalink
Post by Rainer Weikusat
Post by Helmut Schellong
[...]
Post by Ralf Damaschke
Post by Helmut Schellong
Post by Ralf Damaschke
Absatz 2 beschreibt das Verhalten bei zu wenigen 'scanf("%ld")' oder
zu vielen 'scanf(".", &i)' Argumenten.
Absatz 2 beschreibt ebenfalls das Verhalten, wenn Format
und Argumente nicht zueinander passen.
Nur in Bezug auf Diskrepanzen zwischen Format und Anzahl der
Argumente: "insufficient" = nicht genügend viele, oder eben
"excess" = überschüssige.
insufficient = unzulänglich, mangelhaft, ungenügend, ...
-----------------------------------------------------------------
If there are insufficient arguments for the format, the behavior
is undefined.
If the format is exhausted while arguments remain, the excess
arguments are evaluated (as always) but are otherwise ignored.
-----------------------------------------------------------------
Er nennt übrig bleibende und überzählige Argumente, und
bezieht sich damit eindeutig auf die Anzahl der Argumente.
"Falls da sind unzulängliche Argumente für das Format"
Dann ist die Aussage zum ersten Satz arg zweifelhaft.
Auf Deutsch heisst das "Wenn nicht genueged Argumente fuer das Format
"genuegend"

Mit "unzulaenglichen Argumenten" befasst sich Abschnitt 10:

If this object does not have an appropriate type, or if the
result of the conversion cannot be represented the object, the
behavior is undefined.
Helmut Schellong
2018-09-19 17:34:16 UTC
Antworten
Permalink
[...]
Post by Rainer Weikusat
Post by Helmut Schellong
Er nennt übrig bleibende und überzählige Argumente, und
bezieht sich damit eindeutig auf die Anzahl der Argumente.
"Falls da sind unzulängliche Argumente für das Format"
Dann ist die Aussage zum ersten Satz arg zweifelhaft.
Auf Deutsch heisst das "Wenn nicht genueged Argumente fuer das Format
vorhanden sind, ist das Verhalten undefiniert".
Ich kann das akzeptieren, weil der zweite Satz sich eindeutig auf
die Anzahl bezieht.

Warum schreibt der Standard das nicht eindeutig formuliert?
Z.B.: "if there are less arguments than format specifiers"
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2018-09-19 19:35:48 UTC
Antworten
Permalink
Post by Helmut Schellong
[...]
Post by Rainer Weikusat
Post by Helmut Schellong
Er nennt übrig bleibende und überzählige Argumente, und
bezieht sich damit eindeutig auf die Anzahl der Argumente.
"Falls da sind unzulängliche Argumente für das Format"
Dann ist die Aussage zum ersten Satz arg zweifelhaft.
Auf Deutsch heisst das "Wenn nicht genueged Argumente fuer das Format
vorhanden sind, ist das Verhalten undefiniert".
Ich kann das akzeptieren, weil der zweite Satz sich eindeutig auf
die Anzahl bezieht.
Warum schreibt der Standard das nicht eindeutig formuliert?
Z.B.: "if there are less arguments than format specifiers"
Im Englischen ist das eindeutig: Eine Woerterbucherklaerung von
'sufficient' ist 'enough for a particular purpose; as much as you need',

https://www.oxfordlearnersdictionaries.com/definition/english/sufficient?q=sufficient

dh "genug/ genuegend fuer einen bestimmte Zweck, so viel wie gebraucht
wird". Insufficient ist einfach das Gegenteil davon: Weniger als
gebraucht wuerde.
Helmut Schellong
2018-09-19 20:48:21 UTC
Antworten
Permalink
[...]
Post by Rainer Weikusat
Post by Helmut Schellong
Warum schreibt der Standard das nicht eindeutig formuliert?
Z.B.: "if there are less arguments than format specifiers"
Im Englischen ist das eindeutig: Eine Woerterbucherklaerung von
'sufficient' ist 'enough for a particular purpose; as much as you need',
https://www.oxfordlearnersdictionaries.com/definition/english/sufficient?q=sufficient
dh "genug/ genuegend fuer einen bestimmte Zweck, so viel wie gebraucht
wird". Insufficient ist einfach das Gegenteil davon: Weniger als
gebraucht wuerde.
Ja, ich habe ein dickes Buch: Oxford Advanced Learner's Dictionary.
Da steht das auch als Mengen/Anzahl beschreibendes Wort.
Ich habe dann bisher dieses Wort semantisch falsch eingeordnet.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Ralf Damaschke
2018-09-19 23:44:39 UTC
Antworten
Permalink
Post by Helmut Schellong
Post by Ralf Damaschke
Post by Helmut Schellong
Es ist nicht klar, ob zu große Zahlen in der Eingabe
eine 'matching sequence' sind oder nicht.
Doch, das wird exakt bei der Beschreibung der fscanf-Konvertierung
"%d" vorgegeben.
Ich meinte, ob sie matchen, oder nicht und daher weggeworfen werden.
Also weggeworfen wird gar nichts. Ich nehme mal an, dass Du wissen
möchtest, wie weit die Eingabe einer (u.U. riesigen) Zahl konsumiert
wird. Die Anwort ist: vollständig, also die gesamte Folge '[sign]digit*'
sowie vorstehender Leerraum. Ersteres ist zu finden - wie ich schon
schrieb - in der Beschreibung der "%d"-Konvertierung, die wiederum auf
strtol() mit base=10 verweist (wohlgemerkt nur für das Eingabe-Format,
nicht der Konvertierung!). Dort hättest Du dann gefunden:

| 4 The subject sequence is defined as the longest initial subsequence
| of the input string, starting with the first non-white-space
| character, that is of the expected form.
Stefan Ram
2018-09-15 17:39:11 UTC
Antworten
Permalink
Post by Thomas Koenig
Ein Programm soll eine Ganzzahl von standard input einlesen lesen,
um eins erhöhen und auf standard output ausgeben. Für den Fall,
dass dies nicht möglich ist, soll ein Fehlschlag an die Umgebung
signalisiert werden, ansonsten Erfolg. Das Programm soll der
C89-Norm entsprechen.
main.c

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>

int addintintoverflow( int const i, int const j )
{ return
i > 0 && j > 0 && i >( INT_MAX - j )||
i < 0 && j < 0 && i <( INT_MIN - j ); }

int mulintintoverflow( int const i, int const j )
{ if( i > 0 )
{ if( j > 0 ){ if( i > INT_MAX / j )return 1; }
else { if( j < INT_MIN / i )return 2; }}
else
{ if( j > 0 ){ if ( i < INT_MIN / j )return 3; }
else if ( i != 0 && j < INT_MAX / i )return 4; }
return 0; }

int add( int const i, int const j )
{ if( addintintoverflow( i, j ))
return fprintf( stderr, "overflow.\n" ), EXIT_FAILURE;
return printf( "%d\n", i+j ) > 0 ? EXIT_SUCCESS : EXIT_FAILURE; }

int read( int * p )
{ int ch;
while( ch = getchar(), isspace( ch ));
if( ch < 0 )return 0;
if( ch == '-' )
fprintf( stderr, "minus sign not yet implemented.\n" ), exit( 99 );
int value;
if( !isdigit(( unsigned char )ch ))return 0; else
{ value = ch - '0';
int ch; while( ch = getchar(), isdigit(( unsigned char )ch ))
{ if( mulintintoverflow( value, 10 ))return 0;
value = value * 10;
int const v = ch - '0';
if( addintintoverflow( value, v ))return 0;
value = value + v;
continue; }}
*p = value; return 1; }

int main( void )
{ int i, j; if( read( &i ))return add( i, 1 );
fprintf( stderr, "input error.\n" ); return EXIT_FAILURE; }

transcript

2147483646
2147483647

transcript

2147483647
overflow.

transcript

2147483648
input error.
Stefan Ram
2018-09-15 18:44:35 UTC
Antworten
Permalink
Post by Stefan Ram
transcript
2147483646
2147483647
Zum Vergleich: Richtige Programmiersprachen für
professionelle Programmierung enthalten dies
alles bereits von Anfang an:

*** COMMODORE BASIC ***

8192 BYTES FREE

READY.
10 INPUT N%
20 N%=N%+1
30 PRINT N%

RUN
? 32766
32767
READY.

RUN
? 32767
?ILLEGAL QUANTITY ERROR IN 20
READY.

RUN
? 32768
?ILLEGAL QUANTITY ERROR IN 10
READY.
Thomas Koenig
2018-09-15 20:28:34 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Stefan Ram
transcript
2147483646
2147483647
Zum Vergleich: Richtige Programmiersprachen für
professionelle Programmierung enthalten dies
*** COMMODORE BASIC ***
8192 BYTES FREE
RUN
? 32767
?ILLEGAL QUANTITY ERROR IN 20
READY.
Das.

Tut.

Weh.

Immerhin kommen moderne Compiler ein bisschen an den alten Glanz
heran, den die Systeme aus jener goldenen Zeit der Informatik
heute noch verbreiten:

$ gcc -fsanitize=undefined undef.c
$ ./a.out
9223372036854775807
undef.c:10:4: runtime error: signed integer overflow:
9223372036854775807 + 1 cannot be represented in type 'long int'
-9223372036854775808
Rainer Weikusat
2018-09-16 15:41:53 UTC
Antworten
Permalink
Post by Stefan Ram
Post by Stefan Ram
transcript
2147483646
2147483647
Zum Vergleich: Richtige Programmiersprachen für
professionelle Programmierung enthalten dies
*** COMMODORE BASIC ***
8192 BYTES FREE
READY.
10 INPUT N%
20 N%=N%+1
30 PRINT N%
RUN
? 32766
32767
READY.
RUN
? 32767
?ILLEGAL QUANTITY ERROR IN 20
READY.
Es gibt nun mal verschiedene Methoden, wie man Ganzahloperationen, deren
Resultat mit einer bestimmten, festen Anzahl Bit nicht dargestellt
werden kann, behandelt, und die Annahme, diese seien als fehlerhaft anzusehen,
liegt nur manchen zugrunde.

Mal eine andere:

[***@doppelsaurus]~#perl -le 'print 0xffffffffffffffff - 1'
18446744073709551614
[***@doppelsaurus]~#perl -le 'print 0xffffffffffffffff + 1'
1.84467440737096e+19

Hier transparent eine Fliesskommaaddition vorgenommen, weil sich das
Ergenis dann darstellen laesst.
Loading...