Discussion:
Eine Erklaerung fuer a[i] vs i[a]
(zu alt für eine Antwort)
Rainer Weikusat
2018-04-24 19:27:45 UTC
Permalink
Bislang hatte ich das fuer einen mehr oder minder unbeabsichtigten
Seiteneffekt einer fruehen Compiler-Implementierung gehalten. Allerdings
handelt es sich in Wirklichkeit um eine zweifellos beabsichtiges
B-Kompatibilitaetsfeature:

Bestandteil der Laufzeitumgebung eine B-Programms ist ein Speicherfeld
dessen einzelne Zellen jeweils in Wort speichern koennen und von 0 .. n
fortlaufend addressiert sind. Ein B-Feld wird durch eine Speicherzelle,
deren Inhalt die Addresse einer andern Speicherzelle ist,
repraesentiert. Seien also a und i symbolische Namen fuer zwei dieser
Speicherstellen so ist a[i] das i-te Element des Feldes, dessen Adresse
in a steht, und i[a] das a-te Element des Feldes, dessen Addresse in i
gespeichert ist. Relativ zum Anfang des Speicherfeldes ist das in beiden
Faellen diesselbe Speicherzelle.
Juergen Ilse
2018-04-25 03:36:12 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Bislang hatte ich das fuer einen mehr oder minder unbeabsichtigten
Seiteneffekt einer fruehen Compiler-Implementierung gehalten. Allerdings
handelt es sich in Wirklichkeit um eine zweifellos beabsichtiges
Bestandteil der Laufzeitumgebung eine B-Programms ist ein Speicherfeld
dessen einzelne Zellen jeweils in Wort speichern koennen und von 0 .. n
fortlaufend addressiert sind. Ein B-Feld wird durch eine Speicherzelle,
deren Inhalt die Addresse einer andern Speicherzelle ist,
repraesentiert. Seien also a und i symbolische Namen fuer zwei dieser
Speicherstellen so ist a[i] das i-te Element des Feldes, dessen Adresse
in a steht, und i[a] das a-te Element des Feldes, dessen Addresse in i
gespeichert ist. Relativ zum Anfang des Speicherfeldes ist das in beiden
Faellen diesselbe Speicherzelle.
Ich denke nicht, dass es hier um "Kompatibilitaet mit B" geht. Vielmehr ist
letztendlinch a[i] nur etwas wie eine alternative Schreibweise fuer den Aus-
druck *((a)+(i)). Aufgrund der Kommutativitaet der Addition (auch bei Addi-
tion von Pointer und integer) ergibt sich die Gleichhheit von a[i] und i[a].

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Rainer Weikusat
2018-04-25 13:59:12 UTC
Permalink
Post by Juergen Ilse
Post by Rainer Weikusat
Bislang hatte ich das fuer einen mehr oder minder unbeabsichtigten
Seiteneffekt einer fruehen Compiler-Implementierung gehalten. Allerdings
handelt es sich in Wirklichkeit um eine zweifellos beabsichtiges
Bestandteil der Laufzeitumgebung eine B-Programms ist ein Speicherfeld
dessen einzelne Zellen jeweils in Wort speichern koennen und von 0 .. n
fortlaufend addressiert sind. Ein B-Feld wird durch eine Speicherzelle,
deren Inhalt die Addresse einer andern Speicherzelle ist,
repraesentiert. Seien also a und i symbolische Namen fuer zwei dieser
Speicherstellen so ist a[i] das i-te Element des Feldes, dessen Adresse
in a steht, und i[a] das a-te Element des Feldes, dessen Addresse in i
gespeichert ist. Relativ zum Anfang des Speicherfeldes ist das in beiden
Faellen diesselbe Speicherzelle.
Ich denke nicht, dass es hier um "Kompatibilitaet mit B" geht. Vielmehr ist
letztendlinch a[i] nur etwas wie eine alternative Schreibweise fuer den Aus-
druck *((a)+(i)). Aufgrund der Kommutativitaet der Addition (auch bei Addi-
tion von Pointer und integer) ergibt sich die Gleichhheit von a[i] und i[a].
Aufgrund der Kommutativitaet der Addition ergibt sich hier ueberhaupt
gar nichts, denn a[i] ist keine Addition. Es per Definition equivalent
zu *(a + i) oder auch *(i + a) weil letzteres per C-Definition identisch
zu ersterem ist obwohl a und i unterschiedliche Typen haben. Daraus
folgt jetzt aber nichts ueber einen Ausdruck i[a]. Dieser ist
gleichwertig zu a[i] weil das ausdruecklich so definiert ist.

Das beanwortet allerding nicht die Frage, warum das so definiert
ist. Wie man "The Development of the C Language" unschwer entnehmen
kann, war weitestmoegliche Kompatibilitaet zu B beabsichtigt[*], um
existierenden Code, vor allem ein fruehe Yacc-Version, mit moeglichst
geringem Aufwand weiternutzen zu koennen. Und in B ist die Aequivalenz
von a[i] und i[a] ein logisches Resultat der Speicherorganisation und
nicht bloss etwas, worueber Leute dann und wann schlechte Witze machem,
wenn sie etwas unfreundliches ueber C sagen wollen.

[*] Using assembler was dreary enough that B, despite its performance
problems, had been supplemented by a small library of useful service
routines and was being used for more and more new programs. Among
the more notable results of this period was Steve Johnson's first
version of the yacc parser-generator.

[...]

This invention ['pointer to first element'] enabled most existing B
code to continue to work, despite the underlying shift in the
language's semantics.
Thomas Koenig
2018-04-26 18:25:55 UTC
Permalink
Post by Rainer Weikusat
Aufgrund der Kommutativitaet der Addition ergibt sich hier ueberhaupt
gar nichts, denn a[i] ist keine Addition.
Nicht ganz, es steht ja auch noch das * davor...
Post by Rainer Weikusat
Es per Definition equivalent
zu *(a + i)
Korrekt. Das ist ein Ausdruck, der in C sowohl für einen Pointer
a und ein int i als auch umgekehrt definiert wird. Wenn man
Pointer-Arithmetik zulässt, ist sowas durchaus sinnvoll.
Post by Rainer Weikusat
oder auch *(i + a) weil letzteres per C-Definition identisch
zu ersterem ist obwohl a und i unterschiedliche Typen haben. Daraus
folgt jetzt aber nichts ueber einen Ausdruck i[a]. Dieser ist
gleichwertig zu a[i] weil das ausdruecklich so definiert ist.
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.

Es ist also durchaus sinnvoll, (a+i) und (i+a) gleich zu behandeln,
unabhängig von den Typen, und damit auch *(a+i] und *(i+a).

Wenn man darüber noch syntaktischen Zucker gießt und a[i]
als *(a+i) definiert, ist die Äquvialent von a[i] und i[a]
durchaus zu verstehen: Man hat sich einfach eine (nicht nötige)
Einschränkung gespart.

Kompatibilität mit B mag bei dieser Entscheidung eine Rolle gespielt
haben oder auch nicht, das kann ich nicht beurteilen.
Rainer Weikusat
2018-04-26 19:13:43 UTC
Permalink
Post by Thomas Koenig
Post by Rainer Weikusat
Aufgrund der Kommutativitaet der Addition ergibt sich hier ueberhaupt
gar nichts, denn a[i] ist keine Addition.
Nicht ganz, es steht ja auch noch das * davor...
Das ist fuer das 'irgendein +-Operator, der auf irgendwelchen irgendwo
irgendwie definitert ist hat Eigenschaft ... UND DESHALB ...'-Argument
belanglos.
Post by Thomas Koenig
Post by Rainer Weikusat
Es per Definition equivalent
zu *(a + i)
Korrekt. Das ist ein Ausdruck, der in C sowohl für einen Pointer
a und ein int i als auch umgekehrt definiert wird. Wenn man
Pointer-Arithmetik zulässt, ist sowas durchaus sinnvoll.
Zeigerarithmetik ist das C-Aequivalent von B-Addressarithmetik.
Post by Thomas Koenig
Post by Rainer Weikusat
oder auch *(i + a) weil letzteres per C-Definition identisch
zu ersterem ist obwohl a und i unterschiedliche Typen haben. Daraus
folgt jetzt aber nichts ueber einen Ausdruck i[a]. Dieser ist
gleichwertig zu a[i] weil das ausdruecklich so definiert ist.
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Hier koennte man genau umgekehrt argumentierern: Sei a ein Zeiger und b
eine Ganzahl, dann ist das Resultat von a + b ein Zeiger und das von b +
a eine Zahl. Es ist durchaus 'asymmetrisch' in einem Fall den Typ des
ersten und im anderen Fall den Typ des zweiten Arguments den des
Ergebnisses bestimmen zu lassen ...
Post by Thomas Koenig
Es ist also durchaus sinnvoll, (a+i) und (i+a) gleich zu behandeln,
unabhängig von den Typen, und damit auch *(a+i] und *(i+a).
... allerdings ist es egal, was man hier fuer 'durchaus sinnvoll' haelt:
Die Semantik von C-Ausdruecken wird durch die C-Sprachdefinition
bestimmt und insofern diese der Semantik von anderen Ausdruecken
aehnelt, dient das lediglich dazu, Kompatibilitaet mit existierenden
Vorurteilen zu waren.

[...]
Post by Thomas Koenig
Kompatibilität mit B mag bei dieser Entscheidung eine Rolle gespielt
haben oder auch nicht, das kann ich nicht beurteilen.
Das kann man aufgrund der existierenden Literatur zu diesem Thema sehr
wohl beurteilen:

Because pointers in BCPL and B are merely integer indices in the
memory array, arithmetic on them is meaningful: if p is the
address of a cell, then p+1 is the address of the next cell. This
convention is the basis for the semantics of arrays in both
languages. When in BCPL one writes

let V = vec 10

or in B,

auto V[10];

the effect is the same: a cell named V is allocated, then another
group of 10 contiguous cells is set aside, and the memory index
of the first of these is placed into V. By a general rule, in B
the expression

*(V+i)

adds V and i, and refers to the i-th location after V. Both BCPL
and B each add special notation to sweeten such array accesses;
in B an equivalent expression is

V[i]

and in BCPL

V!i

This approach to arrays was unusual even at the time; C would
later assimilate it in an even less conventional way.

["Development of C", S. 4, siehe auch S. 6, 7, "The Problems of
B" und "Embryonic C"]
Juergen Ilse
2018-04-27 03:10:15 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Post by Thomas Koenig
Post by Rainer Weikusat
Es per Definition equivalent
zu *(a + i)
Korrekt. Das ist ein Ausdruck, der in C sowohl für einen Pointer
a und ein int i als auch umgekehrt definiert wird. Wenn man
Pointer-Arithmetik zulässt, ist sowas durchaus sinnvoll.
Zeigerarithmetik ist das C-Aequivalent von B-Addressarithmetik.
Korrekt, aber irrelevant.
Post by Rainer Weikusat
Post by Thomas Koenig
Post by Rainer Weikusat
oder auch *(i + a) weil letzteres per C-Definition identisch
zu ersterem ist obwohl a und i unterschiedliche Typen haben. Daraus
folgt jetzt aber nichts ueber einen Ausdruck i[a]. Dieser ist
gleichwertig zu a[i] weil das ausdruecklich so definiert ist.
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Hier koennte man genau umgekehrt argumentierern: Sei a ein Zeiger und b
eine Ganzahl, dann ist das Resultat von a + b ein Zeiger und das von b +
a eine Zahl. Es ist durchaus 'asymmetrisch' in einem Fall den Typ des
ersten und im anderen Fall den Typ des zweiten Arguments den des
Ergebnisses bestimmen zu lassen ...
Das waere unlogisch und inkonsistent gewesen. Es waere ja auch niemand
auf die Idee gekommen, die Summe aus einem "double" und einem "int" als
vom Typ double festzulegen, waehrend man die Summe aus einem "int" und
einem "double" als vom Typ "int" festlegt (OK, bei manchen objektorien-
tierten Sprachen waere so etwas denkbar, aner bei einer prozeduralen
Sprache waere so etwas mehr als ueberraschend).

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Rainer Weikusat
2018-04-27 13:41:07 UTC
Permalink
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Thomas Koenig
Post by Rainer Weikusat
Es per Definition equivalent
zu *(a + i)
Korrekt. Das ist ein Ausdruck, der in C sowohl für einen Pointer
a und ein int i als auch umgekehrt definiert wird. Wenn man
Pointer-Arithmetik zulässt, ist sowas durchaus sinnvoll.
Zeigerarithmetik ist das C-Aequivalent von B-Addressarithmetik.
Korrekt, aber irrelevant.
Das ist, wie aus den entsprechenden Quellen folgt, keineswegs
irrelevant.
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Thomas Koenig
Post by Rainer Weikusat
oder auch *(i + a) weil letzteres per C-Definition identisch
zu ersterem ist obwohl a und i unterschiedliche Typen haben. Daraus
folgt jetzt aber nichts ueber einen Ausdruck i[a]. Dieser ist
gleichwertig zu a[i] weil das ausdruecklich so definiert ist.
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Hier koennte man genau umgekehrt argumentierern: Sei a ein Zeiger und b
eine Ganzahl, dann ist das Resultat von a + b ein Zeiger und das von b +
a eine Zahl. Es ist durchaus 'asymmetrisch' in einem Fall den Typ des
ersten und im anderen Fall den Typ des zweiten Arguments den des
Ergebnisses bestimmen zu lassen ...
Das waere unlogisch und inkonsistent gewesen. Es waere ja auch niemand
auf die Idee gekommen, die Summe aus einem "double" und einem "int" als
vom Typ double festzulegen, waehrend man die Summe aus einem "int" und
einem "double" als vom Typ "int" festlegt.
Das Beispiel passt hier extrem schlecht: Die Summe zweier Zahlen wird
automatisch in einen Ergebnistyp konvertiert. Der kann sowohl int als
auch double als auch jeder andere Zahlentyp sein. Zb ist das hier

double d0 = 10000.0001, double d1 = 12345678.91011;
unsigned char c;

c = d0 + d1;

legitim.

Im Gegensatz zu B unterscheidet C aber zwischen Zeigern und
Zahlen. Falls dafuer ein +-Operator definiert wird, kann der vollkommen
beliebige Eigenschaften haben.

Das ist aber ein Nebenkriegsschauplatz: Sei a ein Zeiger und i eine Zahl
so gewinnt die Sprache nichts an Ausdrucksfaehiget dadurch, sowohl a[i]
als auch i[a] zu erlauben: Eine dieser beiden Varianten ist schlicht
ueberfluessig. Es waere abstrakt sinnvoller, nur ein Schreibweise zu
erlauben, weil das ohne technischen Nachteile zu weniger
variantenreichem Code fuehren wuerde (und zu weniger 'geistreichen'
Auslassungen ueber 'inherent seltsame C-Syntax').

In B stellt sich die Sache anders dar: Dort sind a[i] und i[a]
equivalent weil beide Speicherzellen sowohl als Zahl als auch als
Adresse intepretiert werden koennen: Es handelt sich nicht um zwei
unterschiedliche Schreibweisen fuer denselben Ausduck ('Element i von
Feld a') sondern um zwei unterschiedliche Ausdruecke ('Element i von
Feld a' und 'Element a von Feld i'), die denselben Wert haben.

Dieses Feature hat sich aus praktischen Gruenden nach C heruebergerettet
obwohl es im C-Typsystem keinen technischen Sinn mehr hat: Wenn sowohl i
als auch n Ganzahlen sind, hat der Ausruck i[n] keine definierte
Bedeutung. Dasselbe gilt fuer zwei Zeiger p und b.

Wie bereits geschriebenL Fuer eine lange Zeit habe ich a[i]/ i[a] fuer
eine aus Rueckwaertskompatibilitaetsgruenden konservierte 'Abkuerzung'
einer fruehen C-Implementierung gehalten, dh essentiell fuer aufgrund
von Massetraegheit konservierte Faulheit. Der Gedanke, dass das
tatsaechlich mal einen Sinn hatte, waere mir nicht von alleine gekommen.
Juergen Ilse
2018-04-27 14:18:17 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Zeigerarithmetik ist das C-Aequivalent von B-Addressarithmetik.
Korrekt, aber irrelevant.
Das ist, wie aus den entsprechenden Quellen folgt, keineswegs
irrelevant.
Doch ist es, selbst wenn die Intention evt. auf die Sprache B (oder BCPL)
zurueckgeht. Es waere inkonsequent und unlogisch, die Operator "+" fuer
alle Datentypen kommutativ zu machen, nicht aber fuer Pointer-Arithmetik.
Man wuerde auch nicht wirklich Vorteile daraus erhalten, bei Pointer-
Arithmetik (und *nur* bei der) die Kommutativitaet des "+" Operators
ueber Board zu werfen. Und wenn man die beibehaelt (was das logische
waere), dann ergibt sich eben auch die abstrus anmutende Moeglichkeit,
einen Pointer als Index fuer einen Integer-Wert zu verwenden (und das
voellig unabhaengig von den Sprachen B und BCPL).
Post by Rainer Weikusat
Das ist aber ein Nebenkriegsschauplatz: Sei a ein Zeiger und i eine Zahl
so gewinnt die Sprache nichts an Ausdrucksfaehiget dadurch, sowohl a[i]
als auch i[a] zu erlauben: Eine dieser beiden Varianten ist schlicht
ueberfluessig.
Wuerde man alles, was ggfs. ueberfluessig sein koennte aus der Sprache
herausstreichen, haette das Ergebnis nichts mehr mit C zu tun ...
Es ist schlicht so, dass der "+" Operator bei allen anderen Typen kommu-
tativ ist, und man gewinnt nichts dadurch, wenn man diese Kommutativitaet
explizit fuer den Fall "Pointer-Arithmetik" (und nur dort) aussschliessen
wuerde.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Rainer Weikusat
2018-04-27 16:01:47 UTC
Permalink
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Zeigerarithmetik ist das C-Aequivalent von B-Addressarithmetik.
Korrekt, aber irrelevant.
Das ist, wie aus den entsprechenden Quellen folgt, keineswegs
irrelevant.
Doch ist es, selbst wenn die Intention evt. auf die Sprache B (oder BCPL)
zurueckgeht. Es waere inkonsequent und unlogisch, die Operator "+" fuer
alle Datentypen kommutativ zu machen, nicht aber fuer
Pointer-Arithmetik.
"Kommutativitaet das +-Operators" auf einer bestimmten Menge existiert
ausschliesslich deswegen, weil dieser Operator so definiert wurde. Das
ist ein Axiom und somit weder 'logisch' noch 'unlogisch' denn es folgt
aus nichts.
Post by Juergen Ilse
Post by Rainer Weikusat
Das ist aber ein Nebenkriegsschauplatz: Sei a ein Zeiger und i eine Zahl
so gewinnt die Sprache nichts an Ausdrucksfaehiget dadurch, sowohl a[i]
als auch i[a] zu erlauben: Eine dieser beiden Varianten ist schlicht
ueberfluessig.
Wuerde man alles, was ggfs. ueberfluessig sein koennte aus der Sprache
herausstreichen, haette das Ergebnis nichts mehr mit C zu tun ...
Die interessante Frage hier waere: Warum wurde es aufgenommen obwohl es
technisch ueberfluessig ist und sich von Konventionen anderer Sprachen
unterscheidet.

Ich nehme aber gerne zur Kenntnis das "Dennis Ritchie war ein Trottel,
der das bizarre um seiner selbst willen anstrebte" manchen Leuten als
Ersatztheorie zu lieb ist, als das sie von ihr lassen wollten. Ein
Schuft wer dabei schlechtes denkt ...
Rainer Weikusat
2018-04-27 16:10:02 UTC
Permalink
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Zeigerarithmetik ist das C-Aequivalent von B-Addressarithmetik.
Korrekt, aber irrelevant.
Das ist, wie aus den entsprechenden Quellen folgt, keineswegs
irrelevant.
Doch ist es, selbst wenn die Intention evt. auf die Sprache B (oder BCPL)
zurueckgeht. Es waere inkonsequent und unlogisch, die Operator "+" fuer
alle Datentypen kommutativ zu machen, nicht aber fuer
Pointer-Arithmetik.
"Kommutativitaet das +-Operators" auf einer bestimmten Menge existiert
ausschliesslich deswegen, weil dieser Operator so definiert wurde. Das
ist ein Axiom und somit weder 'logisch' noch 'unlogisch' denn es folgt
aus nichts.
Davon ab hat "der +-Operator", egal auf welcher Menge definiert, in
dieser Diskussion nichts zu suchen. Die zielte auf den
postfix-[]-Operator in C ab.
Juergen Ilse
2018-04-28 02:16:55 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Davon ab hat "der +-Operator", egal auf welcher Menge definiert, in
dieser Diskussion nichts zu suchen. Die zielte auf den
postfix-[]-Operator in C ab.
Man kann nicht einerseits behaupten a[i] ist per Definition das selbe
wie *((a)+(i))) und andererseits behaupten, der [] Operator haette nichts
mit dem + Operator zu tun. In der ersten Aussage steht bereits der Zusam-
menhang beider Operatren, da kann man nicht gleichzeitig diesen Zusammen-
hang leiugnen, wenn man die erste Aussage als gegeben hinnimmt.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Rainer Weikusat
2018-04-29 17:51:51 UTC
Permalink
Post by Juergen Ilse
Post by Rainer Weikusat
Davon ab hat "der +-Operator", egal auf welcher Menge definiert, in
dieser Diskussion nichts zu suchen. Die zielte auf den
postfix-[]-Operator in C ab.
Man kann nicht einerseits behaupten a[i] ist per Definition das selbe
wie *((a)+(i))) und andererseits behaupten, der [] Operator haette nichts
mit dem + Operator zu tun.
Die Eigenschaften des []-Operators werden in Abschnitt 6.5.2.1 der
C-Norm definiert. Dort steht

One of the expressions shall have type ``pointer to object
type'', the other expression shall have integer type, and the
result has type ``type''.

Diese Definition wegen sind E1[E2] und E2[E1] gleichwertig, nicht
aufgrund irgendwelcher mehr oder minder an den Haaren herbeigezogener
'Schulmathematik'. Der Satz koennte genausogut lauten "The first
expression shall have type 'pointer to object type', the other expression
shall have integer type, and [...]" In diesem Fall waere E1[E2]
aequivalent to *((E1) + (E2)) und E2[E1] undefiniertes Verhalten.
Thomas Koenig
2018-04-30 23:58:27 UTC
Permalink
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Davon ab hat "der +-Operator", egal auf welcher Menge definiert, in
dieser Diskussion nichts zu suchen. Die zielte auf den
postfix-[]-Operator in C ab.
Man kann nicht einerseits behaupten a[i] ist per Definition das selbe
wie *((a)+(i))) und andererseits behaupten, der [] Operator haette nichts
mit dem + Operator zu tun.
Die Eigenschaften des []-Operators werden in Abschnitt 6.5.2.1 der
C-Norm definiert. Dort steht
One of the expressions shall have type ``pointer to object
type'', the other expression shall have integer type, and the
result has type ``type''.
Diese Definition wegen sind E1[E2] und E2[E1] gleichwertig, nicht
aufgrund irgendwelcher mehr oder minder an den Haaren herbeigezogener
'Schulmathematik'.
Das ist natürlich korrekt. Nur hattest du selber die Motivation
hinter dieser Regel angesprochen, und die lange vor der ersten
Norm liegende Historie. Dann beschwer dich nicht, wenn jemand
ausser dir die Motivation hinter der Regel diskutiert :-)
Rainer Weikusat
2018-05-01 15:05:50 UTC
Permalink
Post by Thomas Koenig
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Davon ab hat "der +-Operator", egal auf welcher Menge definiert, in
dieser Diskussion nichts zu suchen. Die zielte auf den
postfix-[]-Operator in C ab.
Man kann nicht einerseits behaupten a[i] ist per Definition das selbe
wie *((a)+(i))) und andererseits behaupten, der [] Operator haette nichts
mit dem + Operator zu tun.
Die Eigenschaften des []-Operators werden in Abschnitt 6.5.2.1 der
C-Norm definiert. Dort steht
One of the expressions shall have type ``pointer to object
type'', the other expression shall have integer type, and the
result has type ``type''.
Diese Definition wegen sind E1[E2] und E2[E1] gleichwertig, nicht
aufgrund irgendwelcher mehr oder minder an den Haaren herbeigezogener
'Schulmathematik'.
Das ist natürlich korrekt. Nur hattest du selber die Motivation
hinter dieser Regel angesprochen, und die lange vor der ersten
Norm liegende Historie. Dann beschwer dich nicht, wenn jemand
ausser dir die Motivation hinter der Regel diskutiert :-)
Da sehe ich keinen Widerspruch: Die Bedeutung von [] ist via Addition
definiert. Aber die Vorbedingugen fuer einen wohlgeformten []-Ausdruck
sind das nicht.

Ein "C Reference Manual" von 1975 meint dazu:

,----
| 7.1.5 primary-expression [ expression ]
|
| A primary expression followed by an expression in square brackets is
| a primary expression. The intuitive mean- ing is that of a
| subscript. Usually, the primary expression has type ``pointer to
| . . .'', the subscript expression is int, and the type of the result is
| `` . . . ''. The expression ``E1[E2]'' is identical (by definition) to
| ``* ( ( E1 ) + ( E2 ) ) ''.
`----

Weiterhin wird auf einen Paragraphen 14.3 zur Erklaerung der
Implementierung verwiesen. Dieser beschreibt die automatische
Konvertierung von einem Ausdruck mit Typ 'array of type' in einen mit
Typ 'pointer to type', wiederholt die inhaliche Definition wobei
ausdruecklich von einem Feld E1 und einer Ganzahl E2 gesprochen wird um
mit dem non sequitur

Therefore, despite its asymmetric appearance, subscripting is a
commutative operation.

zu schliessen. Allerdings folgt das keineswegs aus dem Text, das kann
man sich lediglich denken wenn man annmimmt, der Compiler werde E1[E2]
als typblinde Substitution implementieren.

Dem Wortlaut kann man meiner Ansicht nach entnehmen, dass Dennis Ritchie
das keineswege 'logisch' fand.
Juergen Ilse
2018-04-28 02:11:27 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Post by Juergen Ilse
Doch ist es, selbst wenn die Intention evt. auf die Sprache B (oder BCPL)
zurueckgeht. Es waere inkonsequent und unlogisch, die Operator "+" fuer
alle Datentypen kommutativ zu machen, nicht aber fuer
Pointer-Arithmetik.
"Kommutativitaet das +-Operators" auf einer bestimmten Menge existiert
ausschliesslich deswegen, weil dieser Operator so definiert wurde.
... und er wurde so definiert, weil es das ist, was man (bei Kenntnis
dessen, was man so aus der Schulmathematik kennt) von einem Operator "+"
der die Summe seiner Operanden zurueckgibt erwarten wuerde.
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Das ist aber ein Nebenkriegsschauplatz: Sei a ein Zeiger und i eine Zahl
so gewinnt die Sprache nichts an Ausdrucksfaehiget dadurch, sowohl a[i]
als auch i[a] zu erlauben: Eine dieser beiden Varianten ist schlicht
ueberfluessig.
Wuerde man alles, was ggfs. ueberfluessig sein koennte aus der Sprache
herausstreichen, haette das Ergebnis nichts mehr mit C zu tun ...
Die interessante Frage hier waere: Warum wurde es aufgenommen obwohl es
technisch ueberfluessig ist und sich von Konventionen anderer Sprachen
unterscheidet.
Das was C in diesem Punkt von anderen Sprachen unterscheidet, ist die
Festlegung, dass a[i] das selbe wie *((a)+(i)) ist (man beachte die
Klammern, denn ohne sie koennten sich ggfs. semantische Aenderungen
ergeben, wenn es sich bei i nicht um einen einzelnen Wert sondern um
einen komplexeren Ausdruck handeln wuerde). In anderen Sprachen wird
[] als Operator angesehen, der auf arrays und nicht auf pointer ange-
wendet wird, deshalb taucht in anderen Sprachen die Frage gar nicht
erst auf. Wenn man a[i] als *((a)+(i)) festlegt, dann ist es letztlich
nur konsequent, auch i[a] als aequivalenten Ausdruck zuzulassen.
Post by Rainer Weikusat
Ich nehme aber gerne zur Kenntnis das "Dennis Ritchie war ein Trottel,
der das bizarre um seiner selbst willen anstrebte" manchen Leuten als
Ersatztheorie zu lieb ist, als das sie von ihr lassen wollten. Ein
Schuft wer dabei schlechtes denkt ...
Das habe ich nie behauptet.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Hans-Peter Diettrich
2018-05-23 13:55:10 UTC
Permalink
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Thomas Koenig
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Die Semantik wäre dann aber eindeutiger. Man hätte dann einen Datentyp
"array" einführen können, um all das zu beheben, was Pointerarithmetik
so fehlerträchtig macht. Die neueren C/C++ Specs holen das so langsam nach.
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Hier koennte man genau umgekehrt argumentierern: Sei a ein Zeiger und b
eine Ganzahl, dann ist das Resultat von a + b ein Zeiger und das von b +
a eine Zahl. Es ist durchaus 'asymmetrisch' in einem Fall den Typ des
ersten und im anderen Fall den Typ des zweiten Arguments den des
Ergebnisses bestimmen zu lassen ...
Das waere unlogisch und inkonsistent gewesen. Es waere ja auch niemand
auf die Idee gekommen, die Summe aus einem "double" und einem "int" als
vom Typ double festzulegen, waehrend man die Summe aus einem "int" und
einem "double" als vom Typ "int" festlegt.
Das Beispiel passt hier extrem schlecht: Die Summe zweier Zahlen wird
automatisch in einen Ergebnistyp konvertiert. Der kann sowohl int als
auch double als auch jeder andere Zahlentyp sein. Zb ist das hier
double d0 = 10000.0001, double d1 = 12345678.91011;
unsigned char c;
c = d0 + d1;
legitim.
Legitim vielleicht, die Begründung ist aber falsch. Eine Typ-Erweiterung
erfolgt bei der Evaluierung eines Ausdrucks bei Bedarf, und immer in
Richtung des größeren Datentyps. Symmetrie und Reihenfolge spielen
hierbei überhaupt keine Rolle. Entsprechend kommt es bei der Zuweisung
darauf an, ob sich der Typ und Wert des Ausdrucks in den Zieltyp
umwandeln läßt. Erweitern geht auch hier immer, nur beim Verkürzen
sollte mindestens eine Warnung "significant bits lost" o.ä. vom Compiler
kommen.

DoDi
Helmut Schellong
2018-05-24 15:08:25 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Thomas Koenig
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Die Semantik wäre dann aber eindeutiger. Man hätte dann einen Datentyp
"array" einführen können, um all das zu beheben, was Pointerarithmetik so
fehlerträchtig macht. Die neueren C/C++ Specs holen das so langsam nach.
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?

An den Programmierer würden aber Forderungen gestellt, die zuvor
nicht an ihn gestellt wurden.
Das würde in der Summe eine Verschlechterung des Ganzen bewirken.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Heinz Saathoff
2018-05-25 06:21:59 UTC
Permalink
Post by Helmut Schellong
Post by Hans-Peter Diettrich
Post by Thomas Koenig
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Die Semantik wäre dann aber eindeutiger. Man hätte dann einen Datentyp
"array" einführen können, um all das zu beheben, was Pointerarithmetik so
fehlerträchtig macht. Die neueren C/C++ Specs holen das so langsam nach.
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?
Wenn es einen 'richtigen' Datentyp array gäbe, wie z.B. in Pascal,
wäre der Elementzugriff auch nicht über implizite Pointerarithmetik
definiert, sondern nur über operator[].

BTW, in C++ ist die Symmetrie bei selbstdefinierten Operatoren+/- auch
nicht mehr gewährleistet.
Post by Helmut Schellong
An den Programmierer würden aber Forderungen gestellt, die zuvor
nicht an ihn gestellt wurden.
Das würde in der Summe eine Verschlechterung des Ganzen bewirken.
Es würde nur die Rückwärtskompatibilität mit altem Code brechen.


- Heinz
Helmut Schellong
2018-05-25 08:43:07 UTC
Permalink
Post by Heinz Saathoff
Post by Helmut Schellong
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?
[...]
Post by Heinz Saathoff
Post by Helmut Schellong
An den Programmierer würden aber Forderungen gestellt, die zuvor
nicht an ihn gestellt wurden.
Das würde in der Summe eine Verschlechterung des Ganzen bewirken.
Es würde nur die Rückwärtskompatibilität mit altem Code brechen.
Die Wahrscheinlichkeit für Fehler würde kräftig ansteigen.
Die Unsicherheit von Programmierern ebenfalls.
Etc.
--
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-05-25 12:38:16 UTC
Permalink
Post by Helmut Schellong
Post by Hans-Peter Diettrich
Post by Thomas Koenig
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Die Semantik wäre dann aber eindeutiger. Man hätte dann einen Datentyp
"array" einführen können, um all das zu beheben, was Pointerarithmetik so
fehlerträchtig macht. Die neueren C/C++ Specs holen das so langsam nach.
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?
Fuer Zahlen wohl keine. Aber Zeiger sind keine Zahlen auch wenn sie als
solche repraesentiert werden. Im uebrigen fuehrt diese +-Fokussierung
immer noch in die falsche Richtung --- alle diese "Programmiersprachen
mit symmetrischem +" haben (insofern sie Felder unterstuetzen) eine
durchaus unsymmetrische Indexierungsnotation. Sogar die relevanten
(prae-ANSI/ISO) C-Texte stellen [] als asymmetrisch dar. Dass das nicht
der Fall ist, wird lediglich in einer besseren Fussnote eingeraeumt.
Helmut Schellong
2018-05-25 20:55:05 UTC
Permalink
[...]
Post by Rainer Weikusat
Aber Zeiger sind keine Zahlen auch wenn sie als
solche repraesentiert werden.
Es fällt mir schwer, sie nicht als Zahlen zu betrachten,
wenn ich die Definition z.B. des Operators ++ lese.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Stefan Reuther
2018-05-26 15:23:24 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Rainer Weikusat
Aber Zeiger sind keine Zahlen auch wenn sie als
solche repraesentiert werden.
Es fällt mir schwer, sie nicht als Zahlen zu betrachten,
wenn ich die Definition z.B. des Operators ++ lese.
Konzeptuell handelt es sich bei einem Zeiger in C um eine irgendwie
geartete Identifikation eines Objektes, sowie einen Offset in dieses
Objektes. Der Offset ist eine ganz normale Zahl. Da die Operationen, die
der Zeigerarithmetik dienen, alle so eingeschränkt sind, dass sie nur
den Offset innerhalb des Objektes verschieben dürfen, benehmen sich
solche Zeiger halt wie Zahlen.

Aber sobald man diesen Bereich verlässt, beginnt undefiniertes
Verhalten, und dann benehmen sie sich nicht mehr wie Zahlen. Dann ist
eben zum Beispiel p + (q - p) != q (Borland-Compiler, p und q von
malloc, Typ von *p, *q ist irgendwas krummes, z.B. 6 Bytes).


Stefan
Helmut Schellong
2018-05-26 16:27:50 UTC
Permalink
Post by Stefan Reuther
Post by Helmut Schellong
[...]
Post by Rainer Weikusat
Aber Zeiger sind keine Zahlen auch wenn sie als
solche repraesentiert werden.
Es fällt mir schwer, sie nicht als Zahlen zu betrachten,
wenn ich die Definition z.B. des Operators ++ lese.
Konzeptuell handelt es sich bei einem Zeiger in C um eine irgendwie
geartete Identifikation eines Objektes, sowie einen Offset in dieses
Objektes. Der Offset ist eine ganz normale Zahl. Da die Operationen, die
der Zeigerarithmetik dienen, alle so eingeschränkt sind, dass sie nur
den Offset innerhalb des Objektes verschieben dürfen, benehmen sich
solche Zeiger halt wie Zahlen.
Im Standard (++):
the value of the operand object is incremented
(that is, the value 1 of the appropriate type is added to it).

Aufgrund vorstehenden Textes und beispielsweise wegen
6.5.6 und ptrdiff_t sind Zeiger für mich doch (eher) Zahlen,
weil ja der Offset gemeint ist und modifiziert wird.
Nur eines geht nicht: Zeiger + Zeiger.
(Man könnte sagen, weil Zeiger real Zahlen sind.)
--
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-05-26 16:53:26 UTC
Permalink
Post by Stefan Reuther
Post by Helmut Schellong
[...]
Post by Rainer Weikusat
Aber Zeiger sind keine Zahlen auch wenn sie als
solche repraesentiert werden.
Es fällt mir schwer, sie nicht als Zahlen zu betrachten,
wenn ich die Definition z.B. des Operators ++ lese.
Konzeptuell handelt es sich bei einem Zeiger in C um eine irgendwie
geartete Identifikation eines Objektes, sowie einen Offset in dieses
Objektes.
Jeder gueltige C-Zeiger zeigt auf entweder ein Feld von Objekten oder
auf eine gedachtes Endelement hinter dem letzten, tatsaechlichen
Element. Sei p ein Zeiger auf ein Feld der Groesse n, n >= 1, dann sind
p + 1, p + 2, ... p + n Zeiger auf die Folgelemente. Fuer zwei Indices
i, j, 0 <= i <= j, j <= n gilt (unueberaschenderweise) (p + j) - (p + i) = j
- i. Darueber hinausgehend ist Zeigerarithmetik durch die Sprache
undefiniert.

Dh man kann 'legal' Ganzahlen <= n zu p addieren und man kann einen Zeiger
fuer den pp = p + i, 0 <= i <= j gilt, von einem Zeiger ppp = p + j, j <= n
subtrahieren. Sonst nichts. Insbeondere gibt es weder Zeigeraddition
noch -multiplikation oder -divison. Bisschen seltsam fuer eine 'Zahl'
...
Helmut Schellong
2018-05-26 17:53:16 UTC
Permalink
[...]
Post by Rainer Weikusat
- i. Darueber hinausgehend ist Zeigerarithmetik durch die Sprache
undefiniert.
Dh man kann 'legal' Ganzahlen <= n zu p addieren und man kann einen Zeiger
fuer den pp = p + i, 0 <= i <= j gilt, von einem Zeiger ppp = p + j, j <= n
subtrahieren. Sonst nichts. Insbeondere gibt es weder Zeigeraddition
noch -multiplikation oder -divison. Bisschen seltsam fuer eine 'Zahl'
...
Der 'Zahlenbereich' für Zeiger ist per Definition eng begrenzt.
Nämlich ab Offset=0 bis Offset=end+1.
Nur deshalb können einige Operationen nicht vorgenommen werden.

Der Standard definiert auch aufgrund von real vorliegender Hardware,
wo Zeiger eben doch ganz normale Zahlen sind.
(Byte-adressierbare Maschine)
--
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-05-27 11:29:08 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Rainer Weikusat
- i. Darueber hinausgehend ist Zeigerarithmetik durch die Sprache
undefiniert.
Dh man kann 'legal' Ganzahlen <= n zu p addieren und man kann einen Zeiger
fuer den pp = p + i, 0 <= i <= j gilt, von einem Zeiger ppp = p + j, j <= n
subtrahieren. Sonst nichts. Insbeondere gibt es weder Zeigeraddition
noch -multiplikation oder -divison. Bisschen seltsam fuer eine 'Zahl'
...
Der 'Zahlenbereich' für Zeiger ist per Definition eng begrenzt.
Nämlich ab Offset=0 bis Offset=end+1.
Nur deshalb können einige Operationen nicht vorgenommen werden.
Der Standard definiert auch aufgrund von real vorliegender Hardware,
wo Zeiger eben doch ganz normale Zahlen sind.
(Byte-adressierbare Maschine)
'Zeiger' ist ein Hochsprachenkonstrukt. Auf Maschinebene gibt es sowas
nicht. Es gibt Register, die Ganzahlen, deren Repraesentation hoechstens
soundsoviel Bit benoetigt, speichern koennen, und Moeglichkeiten, diese
in Rahmen bestimmter Maschinenbefehle als Speicheraddressen
interpretieren zu lassen. Oder sonstwas, zB Postanschriften, an
die man Karten mit Zahlen drauf verschicken kann und den jeweiligen
Anschrifinhaber instruieren, so unter sonstwas fuer Umstaenden an eine
andere Anschrift zu schicken. Das waere zwar ein bisschen zu langsam, um
etwas kompliziertes zu Berechnen, wuerde aber theoretisch genausgut
funktionieren. 'Zeigerarithmetik' ginge dann fuer all fortlaufenden
Hausnummern einer Strasse.

Das ist auf C-Ebene vollkommen uninteressant, stattdessen gibt es die
Abstraktion 'Zeiger'.
Helmut Schellong
2018-05-28 10:23:47 UTC
Permalink
[...]
Post by Rainer Weikusat
Post by Helmut Schellong
Post by Rainer Weikusat
subtrahieren. Sonst nichts. Insbeondere gibt es weder Zeigeraddition
noch -multiplikation oder -divison. Bisschen seltsam fuer eine 'Zahl'
...
Der 'Zahlenbereich' für Zeiger ist per Definition eng begrenzt.
Nämlich ab Offset=0 bis Offset=end+1.
Nur deshalb können einige Operationen nicht vorgenommen werden.
Der Standard definiert auch aufgrund von real vorliegender Hardware,
wo Zeiger eben doch ganz normale Zahlen sind.
(Byte-adressierbare Maschine)
'Zeiger' ist ein Hochsprachenkonstrukt. Auf Maschinebene gibt es sowas
nicht. Es gibt Register, die Ganzahlen, deren Repraesentation hoechstens
soundsoviel Bit benoetigt, speichern koennen, und Moeglichkeiten, diese
in Rahmen bestimmter Maschinenbefehle als Speicheraddressen
interpretieren zu lassen.
[...]
Das ist auf C-Ebene vollkommen uninteressant, stattdessen gibt es die
Abstraktion 'Zeiger'.
Wenn ich mal annehme: Zeiger ≡ Z + o
dann wäre die vom Standard definierte Operation
Zeiger1 - Zeiger2
Z - Z + o1 - o2

Dabei fordert der Standard bekanntlich, daß zwei Zeiger
hierbei aus ein und demselben Objekt stammen müssen.
Deshalb hat vorstehend Z keinen Index.

Z hebt sich also auf, zu 'Nichts', zu 0.

Da der Standard Addition, Multiplikation, Division
von Zeigern nicht definiert, ist dadurch automatisch
definiert, daß Zeiger keine Zahlen sind?
Ich sehe das jedenfalls nicht.

Der Standard definiert hingegen, daß ++Zeiger
den Zeiger (typgerecht) um 1 erhöht.
Der Standard verwendet nirgendwo die Darstellung 'Z + o'.

Auf Zeiger angewandte Operationen Addition, Multiplikation,
Division, erscheinen gerade dann als nicht anwendbar, wenn
ein Zeiger als Zahl 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
G.B.
2018-05-26 06:17:42 UTC
Permalink
Post by Helmut Schellong
Post by Hans-Peter Diettrich
Post by Thomas Koenig
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Die Semantik wäre dann aber eindeutiger. Man hätte dann einen Datentyp
"array" einführen können, um all das zu beheben, was Pointerarithmetik so
fehlerträchtig macht. Die neueren C/C++ Specs holen das so langsam nach.
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?
In Java ist + zwischen Strings jedenfalls nicht kommutativ.
Helmut Schellong
2018-05-26 10:37:23 UTC
Permalink
[...]
Post by G.B.
Post by Helmut Schellong
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?
In Java ist + zwischen Strings jedenfalls nicht kommutativ.
Dort ist + ja auch ein Verkettungsoperator.

Ich meinte + natürlich als Additionsoperator.

Jetzt soll aber niemand argumentieren, der Resultat-String
ist länger als die Einzel-Strings --> Additionsoperator.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Hans-Peter Diettrich
2018-05-30 21:01:06 UTC
Permalink
Post by Helmut Schellong
[...]
Post by G.B.
Post by Helmut Schellong
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?
In Java ist + zwischen Strings jedenfalls nicht kommutativ.
Dort ist + ja auch ein Verkettungsoperator.
Ich meinte + natürlich als Additionsoperator.
Was kennzeichnet diesen Operator? Ist er auf zwei Pointer anwendbar?

Rein syntaktisch ist der Operator "+" anwendbar auf alle Datentypen, für
die er definiert ist. Und dann macht er das, wofür er implementiert
wurde. Damit ist es nicht zulässig, diesem (literalen) Operator in
irgendeiner Programmiersprache irgendwelche (unabdingbaren)
mathematischen Eigenschaften zuzusprechen.

DoDi
Helmut Schellong
2018-05-31 09:36:54 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Helmut Schellong
[...]
Post by G.B.
Post by Helmut Schellong
Welche Programmiersprache hat unsymmetrische Operatoren »+ -«?
In Java ist + zwischen Strings jedenfalls nicht kommutativ.
Dort ist + ja auch ein Verkettungsoperator.
Ich meinte + natürlich als Additionsoperator.
Was kennzeichnet diesen Operator? Ist er auf zwei Pointer anwendbar?
Er ist gekennzeichnet durch seinen Zahlenwert im Zeichensatz
und durch seine grafische Repräsentation.

Laut C-Standard ist er nicht anwendbar auf zwei Pointer.

Die Bedeutung dieses Zeichens '+' ist beliebig zuzuordnen.
Jeder Kontext kann das machen, wie er will.
Das gilt für alle denkbaren Zeichen.
--
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-05-24 15:41:29 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Thomas Koenig
Man hätte natürlich auch a+i zulassen und i+a verbieten können.
Das wäre aber definitiv eine "Warze" der Programmiersprache
gewesen, den + - Operator asymmetrisch zu machen.
Die Semantik wäre dann aber eindeutiger. Man hätte dann einen Datentyp
"array" einführen können, um all das zu beheben, was Pointerarithmetik
so fehlerträchtig macht.
Das waere?
Post by Hans-Peter Diettrich
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Hier koennte man genau umgekehrt argumentierern: Sei a ein Zeiger und b
eine Ganzahl, dann ist das Resultat von a + b ein Zeiger und das von b +
a eine Zahl. Es ist durchaus 'asymmetrisch' in einem Fall den Typ des
ersten und im anderen Fall den Typ des zweiten Arguments den des
Ergebnisses bestimmen zu lassen ...
Das waere unlogisch und inkonsistent gewesen. Es waere ja auch niemand
auf die Idee gekommen, die Summe aus einem "double" und einem "int" als
vom Typ double festzulegen, waehrend man die Summe aus einem "int" und
einem "double" als vom Typ "int" festlegt.
Das Beispiel passt hier extrem schlecht: Die Summe zweier Zahlen wird
automatisch in einen Ergebnistyp konvertiert. Der kann sowohl int als
auch double als auch jeder andere Zahlentyp sein. Zb ist das hier
double d0 = 10000.0001, double d1 = 12345678.91011;
unsigned char c;
c = d0 + d1;
legitim.
Legitim vielleicht, die Begründung ist aber falsch. Eine
Typ-Erweiterung erfolgt bei der Evaluierung eines Ausdrucks bei
Bedarf, und immer in Richtung des größeren Datentyps.
c = x;

ist ein Ausdruck. Insofern c in x Zahlen sind, wird der Wert von x in
den Typ von C konvertiert.

x + x

ist auch ein Ausdruck. Auch hier wird automatisch konvertiert, falls
notwendig. Das gilt aber nur fuer Zahlen und nicht fuer Zeiger. Sei

int *a;
char *b;

dann ist a - b undefiniert und a = b braucht einen Cast.

[...]
Post by Hans-Peter Diettrich
Erweitern geht auch hier immer, nur
beim Verkürzen sollte mindestens eine Warnung "significant bits lost"
o.ä. vom Compiler kommen.
Das sehe ich nicht so.
Claus Reibenstein
2018-05-24 15:58:17 UTC
Permalink
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Erweitern geht auch hier immer, nur
beim Verkürzen sollte mindestens eine Warnung "significant bits lost"
o.ä. vom Compiler kommen.
Das sehe ich nicht so.
Ich schon, denn das könnte ein Hinweis auf einen potentiellen Fehler
sein. Der Programmierer kann ja, wenn er die Situation erfolgreich
geprüft hat, immer noch casten und damit die Warnung an dieser Stelle
eliminieren.

Gruß
Claus
Rainer Weikusat
2018-05-24 21:32:07 UTC
Permalink
Post by Claus Reibenstein
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Erweitern geht auch hier immer, nur
beim Verkürzen sollte mindestens eine Warnung "significant bits lost"
o.ä. vom Compiler kommen.
Das sehe ich nicht so.
Ich schon, denn das könnte ein Hinweis auf einen potentiellen Fehler
sein. Der Programmierer kann ja, wenn er die Situation erfolgreich
geprüft hat, immer noch casten und damit die Warnung an dieser Stelle
eliminieren.
Auf der Basis derselben Logik koennte man auch eine "Subtraction
operator detected, sure you didn't mean multiplication?" ausgeben
lassen: Alles, was im Code steht, ist potentiell falsch. Eine
"significant bits lost"-Warnung, die von einem Konstrukt dessen Semantik
"drop insignificant bits" ist, ausgeloest wird, ist nichts weiter als eine
politische "Dieses Feature sollte es aber nicht geben !!2"-Aussage
des/der Compilerschreiber.
G.B.
2018-05-26 06:52:54 UTC
Permalink
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Erweitern geht auch hier immer, nur
beim Verkürzen sollte mindestens eine Warnung "significant bits lost"
o.ä. vom Compiler kommen.
Das sehe ich nicht so.
Ich schon, denn das könnte ein Hinweis auf einen potentiellen Fehler
sein. Der Programmierer kann ja, wenn er die Situation erfolgreich
geprüft hat, immer noch casten und damit die Warnung an dieser Stelle
eliminieren.
Auf der Basis derselben Logik koennte man auch eine "Subtraction
operator detected, sure you didn't mean multiplication?"
Auf der Basis einer vergleichbaren, nicht auf derselben Logik,
denn es ist nicht das selbe: Typwandlung ist nicht das selbe
wie Operation + oder -. Die Wandlung ist etwas, das nach den
Regeln implizit auch passiert. + zwischen Zahlen weggelassen
bedeutet keine implizite Addition.

Interpretationen ("mean"), die Entscheidungen für oder gegen
eine Meldung steuern, werden sich an einer Zielgruppe orientieren.
Wenn die Zielgruppe Mitglieder einer Zunft sind, die nach Art
einer Geheimgesellschaft Wissende rekrutiert, mindestens
aber eine eigene Sprechweise entwickelt, dann muss die Meldung
nicht sein: man weiß das ja, sonst Schlitzohr. (Manchmal nennen
die Leute als Zielgruppe auch das eigene Selbst.)

Beim Arbeits-Einsatz einer solchen Gemeinschaft entsteht für die sie
beschäftigenden Menschen die Frage, ob sie das Weglassen (redundanter)
Information nach Maß und Risiko wirtschaftlich tragen sollten.

Wie viel Nicht-Nennung ist beispielsweise gut für ein Team,
das nicht nur aus Leuten besteht, die die C-Norm träumen?

Wie viel Nicht-Nennung ist gut für ein Projekt, dessen
Mitarbeiter zwischen mehreren Sprachen zu wechseln mehrfach
gezwungen sein werden?

Wie viel Nennung geht nach hinten los?

Ich lese gerade zwei Dutzend Zeilen Quelltext, die folgendem
Muster folgen:


Typ1 x = ...;

x.(arg1, arg2)
.op(dudeldi) ({
...
})
.option(dies, das)
.haken(b, c);

Für Leser, die sich implizites Spezialisten-Wissen aneignen konnten,
ist ganz klar,
- was hier was ist
- was hier was tut.

Ist das Weglassen vermeintlich Arbeitsplatzschutz? Immerhin nutzen
Obfuskatoren ähnliche Techniken mit dem Ziel, Interessen zu schützen.
Auch äußern Programmierer ihren Stolz darüber, wenn sie die
Inferenzen auch selbst hinbekommen haben und den Übersetzer
sogar korrigieren können.
Thomas Koenig
2018-05-26 10:24:38 UTC
Permalink
Post by G.B.
Ich lese gerade zwei Dutzend Zeilen Quelltext, die folgendem
Typ1 x = ...;
x.(arg1, arg2)
.op(dudeldi) ({
...
})
.option(dies, das)
.haken(b, c);
Für Leser, die sich implizites Spezialisten-Wissen aneignen konnten,
ist ganz klar,
- was hier was ist
- was hier was tut.
Ist das C?
G.B.
2018-05-26 13:39:02 UTC
Permalink
Post by Thomas Koenig
Post by G.B.
Ich lese gerade zwei Dutzend Zeilen Quelltext, die folgendem
Typ1 x = ...;
x.(arg1, arg2)
.op(dudeldi) ({
...
})
.option(dies, das)
.haken(b, c);
Für Leser, die sich implizites Spezialisten-Wissen aneignen konnten,
ist ganz klar,
- was hier was ist
- was hier was tut.
Ist das C?
Nicht im Original. Das folgende habe ich in C-Quellen auch selten
gesehen, stilistisch:

x.f(arg1, arg2)
.op(dudeldi) (A{
1,2,3
})
.option(dies, das)
.haken(b, c);
Rainer Weikusat
2018-05-26 13:40:38 UTC
Permalink
Post by G.B.
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Erweitern geht auch hier immer, nur
beim Verkürzen sollte mindestens eine Warnung "significant bits lost"
o.ä. vom Compiler kommen.
Das sehe ich nicht so.
Ich schon, denn das könnte ein Hinweis auf einen potentiellen Fehler
sein. Der Programmierer kann ja, wenn er die Situation erfolgreich
geprüft hat, immer noch casten und damit die Warnung an dieser Stelle
eliminieren.
Auf der Basis derselben Logik koennte man auch eine "Subtraction
operator detected, sure you didn't mean multiplication?"
Auf der Basis einer vergleichbaren, nicht auf derselben Logik,
denn es ist nicht das selbe: Typwandlung ist nicht das selbe
wie Operation + oder -. Die Wandlung ist etwas, das nach den
Regeln implizit auch passiert. + zwischen Zahlen weggelassen
bedeutet keine implizite Addition.
Typumwandlungen finden auch nicht 'implizit' statt, wenigstens nicht so,
wie das in obigem Text angedeuted scheint. Sie sind Bestandteil der
Semantik von Zuweisungen.

unsigned char c;
int i = -1;
c = i;

Da steht ausdruecklich. dass ein int-Wert einer Variablen vom Typ
'unsigned char' zugewiesen werden soll. Eine "ich mein das echt
so!"-Ergaenzung

c = (unsigned char)i;

macht das nicht klarer, eher im Gegenteil[*]: Der zusaetzliche Text
stoert.

[*] Vor ein paar Jahren habe ich mir in ungefaehr drei Tagen soviel Java
beigebracht, dass ich ein paar dringend erforderliche Verbesserungen an
einem 'mittelkleine' (so um die 65,000 Zeilen) Java-Projekt vornehmen
konnte, weil das sonst niemand getan haette. Dabei ist mir sehr
graphisch klargeworden, wieviel unleserlicher dieser Text dadurch wurde,
dass seine urspruenglichen Autoren vor alles, wo es syntaktisch erlaubt
war, ein 'final' geklebt hatten, weil das die magische
Beschwoerungsformal erst so richtig magisch macht. Deswegen habe ich
aufgehoert, in C const zu benutzen.

[...]
Post by G.B.
Wie viel Nicht-Nennung ist gut für ein Projekt, dessen
Mitarbeiter zwischen mehreren Sprachen zu wechseln mehrfach
gezwungen sein werden?
Funktionslose Quelltextbestandteile sind genau fuer eines gut: Sie
koennen andernfalls vermiedene Fehler enthalten.
Post by G.B.
Ich lese gerade zwei Dutzend Zeilen Quelltext, die folgendem
Typ1 x = ...;
x.(arg1, arg2)
.op(dudeldi) ({
...
})
.option(dies, das)
.haken(b, c);
Für Leser, die sich implizites Spezialisten-Wissen aneignen konnten,
ist ganz klar,
- was hier was ist
- was hier was tut.
Ist das Weglassen vermeintlich Arbeitsplatzschutz?
Was ist hier weggelassen? Hier wird eine Folge von Methoden, die jeweils
ein Objekt zurueckgeben, verkettet. Das ist zwar Dumm[tm], weil es
Debugging erschwert und Aendern des Code verkompliziert aber vollkommen
durchsichtig.
G.B.
2018-05-26 13:50:11 UTC
Permalink
Post by Rainer Weikusat
Post by G.B.
Ich lese gerade zwei Dutzend Zeilen Quelltext, die folgendem
Typ1 x = ...;
x.(arg1, arg2)
.op(dudeldi) ({
...
})
.option(dies, das)
.haken(b, c);
Für Leser, die sich implizites Spezialisten-Wissen aneignen konnten,
ist ganz klar,
- was hier was ist
- was hier was tut.
Ist das Weglassen vermeintlich Arbeitsplatzschutz?
Was ist hier weggelassen? Hier wird eine Folge von Methoden, die jeweils
ein Objekt zurueckgeben, verkettet. Das ist zwar Dumm[tm], weil es
Debugging erschwert und Aendern des Code verkompliziert aber vollkommen
durchsichtig.
Was ist denn dann unvollkommen durchsichtig?
Rainer Weikusat
2018-05-26 14:23:47 UTC
Permalink
Post by G.B.
Post by Rainer Weikusat
Post by G.B.
Ich lese gerade zwei Dutzend Zeilen Quelltext, die folgendem
Typ1 x = ...;
x.(arg1, arg2)
.op(dudeldi) ({
...
})
.option(dies, das)
.haken(b, c);
Für Leser, die sich implizites Spezialisten-Wissen aneignen konnten,
ist ganz klar,
- was hier was ist
- was hier was tut.
Ist das Weglassen vermeintlich Arbeitsplatzschutz?
Was ist hier weggelassen? Hier wird eine Folge von Methoden, die jeweils
ein Objekt zurueckgeben, verkettet. Das ist zwar Dumm[tm], weil es
Debugging erschwert und Aendern des Code verkompliziert aber vollkommen
durchsichtig.
Was ist denn dann unvollkommen durchsichtig?
Milchglas.

SCNR
Juergen Ilse
2018-05-26 19:06:42 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Typumwandlungen finden auch nicht 'implizit' statt,
Doch.
Post by Rainer Weikusat
Sie sind Bestandteil der Semantik von Zuweisungen.
Das ist kein Widerspruch zur ersten Aussage.
"implizit" == "ohne dass es explizit hingeschrieben wird", und bei einer
Zuweisung oder bei Arithmetik wird die laut Sprachdefinition ggfs. statt-
findende Typumwandlung statt, ohne dass diese explizit hingeschrieben wird,
also *implizit*.
Post by Rainer Weikusat
unsigned char c;
int i = -1;
c = i;
Da steht ausdruecklich. dass ein int-Wert einer Variablen vom Typ
'unsigned char' zugewiesen werden soll. Eine "ich mein das echt
so!"-Ergaenzung
c = (unsigned char)i;
macht das nicht klarer, eher im Gegenteil[*]: Der zusaetzliche Text
stoert.
Geschmacksache.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Rainer Weikusat
2018-05-27 11:39:12 UTC
Permalink
Post by Juergen Ilse
Post by Rainer Weikusat
Typumwandlungen finden auch nicht 'implizit' statt,
Doch.
Post by Rainer Weikusat
Sie sind Bestandteil der Semantik von Zuweisungen.
Das ist kein Widerspruch zur ersten Aussage.
"implizit" == "ohne dass es explizit hingeschrieben wird", und bei einer
Zuweisung oder bei Arithmetik wird die laut Sprachdefinition ggfs. statt-
findende Typumwandlung statt, ohne dass diese explizit hingeschrieben wird,
also *implizit*.
Es wird aber explizit hingeschrieben. Das untenstehende

c = i;

bedeutet "konvertiere den Wert von i in den Typ von c und weise das
Resultat c zu". Das kann man nicht kuenstlich in zwei Teiloperation
"Typkonvertierung" und "Zuweisung" zerlegen, von denen man willkuerlich
eine als explizit und die andere als implizit annimmt. Es bedeutet
beides zusammen. Genausogut (oder -schlecht) koennte man von einer expliziten
Typkonvertierung mit impliziter Zuweisung reden. Sagen wir mal, um
folgende Konvention zu verfechten:

c = /* Will := doch "Ach .." ! Ehrlose Schweinebande !! */ i;

("Wilhelm II kommentiert C-Code")
Post by Juergen Ilse
Post by Rainer Weikusat
unsigned char c;
int i = -1;
c = i;
Da steht ausdruecklich. dass ein int-Wert einer Variablen vom Typ
'unsigned char' zugewiesen werden soll. Eine "ich mein das echt
so!"-Ergaenzung
c = (unsigned char)i;
macht das nicht klarer, eher im Gegenteil[*]: Der zusaetzliche Text
stoert.
Geschmacksache.
"Geschmacksache" ist, ob man solche Redunanzen mag. Aber redundant
bleiben sie.
Juergen Ilse
2018-05-27 20:52:03 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Typumwandlungen finden auch nicht 'implizit' statt,
Doch.
Post by Rainer Weikusat
Sie sind Bestandteil der Semantik von Zuweisungen.
Das ist kein Widerspruch zur ersten Aussage.
"implizit" == "ohne dass es explizit hingeschrieben wird", und bei einer
Zuweisung oder bei Arithmetik wird die laut Sprachdefinition ggfs. statt-
findende Typumwandlung statt, ohne dass diese explizit hingeschrieben wird,
also *implizit*.
Es wird aber explizit hingeschrieben. Das untenstehende
Nein.
Post by Rainer Weikusat
c = i;
... ist eine Zuweisung, die aufgrund der Semantik und der Tatsache der
unterschiedlichen Datentypen von c un i eine Konvertierung erfordert,
die deshalb *IMPLIZIT* i(also ohne dass explizit eine -typumwandlungs-
direktive, sprich ein cast, hingeschrieben wird) durchgefuehrt wird.
Post by Rainer Weikusat
bedeutet "konvertiere den Wert von i in den Typ von c und weise das
Resultat c zu". Das kann man nicht kuenstlich in zwei Teiloperation
"Typkonvertierung" und "Zuweisung" zerlegen,
Es ist nichts "kuenstliches" daran, dass der Standard besagt, dass hier
*zwei* Operationen durchgefuehrt werden (eine Typumwandlung in den Ziel-
typ und die Zuweisung des konvertierten Wertes an die Variable i).
Post by Rainer Weikusat
von denen man willkuerlich eine als explizit und die andere als implizit
annimmt.
Da muss man nichts annehmen. Die Typkonvertierung steht nicht in der An-
weisung, sondern erfolgt implizit (aufgrund der untersxhiedlichen Typen
auf beiden Seiten der Zuweisung). Das "steht nicht ausdruecklich in der
Anweisung sondern ergibt sich nur aus dem Kontext" ist eben das Kriterium
fuer "implizite Typumwandlung". Ergenzt man den (hier nicht zwingend erfor-
derlichen) cast, ist das eine *explizite Typumwandlung, und die implizite
Typumwandlung entfaellt mangels Notwendigkeit.
Post by Rainer Weikusat
Post by Juergen Ilse
Geschmacksache.
"Geschmacksache" ist, ob man solche Redunanzen mag. Aber redundant
bleiben sie.
Das ist kein Widerspruch zum zuvor geschriebenen. Es ist Geschmacksache,
ob man hier eine *explizite* Typumwandlung (in Form eines casts) ergaenzt
oder sich auf die (vom Standard vorgeschriebene) *implizite* Typumwandlung
verlaesst. Implizit bleibt die Typumwandlung bei weglassen des casts dennoch.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Rainer Weikusat
2018-05-27 21:02:01 UTC
Permalink
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Typumwandlungen finden auch nicht 'implizit' statt,
Doch.
Post by Rainer Weikusat
Sie sind Bestandteil der Semantik von Zuweisungen.
Das ist kein Widerspruch zur ersten Aussage.
"implizit" == "ohne dass es explizit hingeschrieben wird", und bei einer
Zuweisung oder bei Arithmetik wird die laut Sprachdefinition ggfs. statt-
findende Typumwandlung statt, ohne dass diese explizit hingeschrieben wird,
also *implizit*.
Es wird aber explizit hingeschrieben. Das untenstehende
Nein.
Post by Rainer Weikusat
c = i;
... ist eine Zuweisung, die aufgrund der Semantik und der Tatsache der
unterschiedlichen Datentypen von c un i eine Konvertierung erfordert,
die deshalb *IMPLIZIT* i(also ohne dass explizit eine -typumwandlungs-
direktive, sprich ein cast, hingeschrieben wird) durchgefuehrt wird.
Zahlenzuweisungen in C beinhalten immer ggf notwendige
Typkonvertierungen. Insofern sind sie explizit Bestandteil der
Operation. Die C-Norm enthaelt hier keine zusaetzlich Qualifizierung:

In simple assignment (=), the value of the right operand is
converted to the type of the assignment expression and replaces
the value stored in the object designated by the left operand.

[...]
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Geschmacksache.
"Geschmacksache" ist, ob man solche Redunanzen mag. Aber redundant
bleiben sie.
Das ist kein Widerspruch zum zuvor geschriebenen. Es ist Geschmacksache,
ob man hier eine *explizite* Typumwandlung (in Form eines casts) ergaenzt
Dadurch, dass man einen bestenfalls ueberfluessigen und schlimmstenfalls
falschen Klammerausdruck vor den R-Wert schreibt, ergaenzt man nichts
(weil die 'imaginaere Operation' Bestandteil der Zuweisung ist) ausser
man fuegt einen Fehler hinzu.
Juergen Ilse
2018-05-27 21:22:34 UTC
Permalink
Hallo,
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Es wird aber explizit hingeschrieben. Das untenstehende
Nein.
Post by Rainer Weikusat
c = i;
... ist eine Zuweisung, die aufgrund der Semantik und der Tatsache der
unterschiedlichen Datentypen von c un i eine Konvertierung erfordert,
die deshalb *IMPLIZIT* i(also ohne dass explizit eine -typumwandlungs-
direktive, sprich ein cast, hingeschrieben wird) durchgefuehrt wird.
Zahlenzuweisungen in C beinhalten immer ggf notwendige
Typkonvertierungen.
Stimmt. Sie beinhalten (bei unterschiedlichen Typen rechts und links vom
Zuweisungsoperator) *zwei* Operationen, von denen eine *implizit* (also
ohne dass sie extra hingeschrieben wird) durchgefuehrt wird.
Post by Rainer Weikusat
Insofern sind sie explizit Bestandteil der
Nach deine Argumentation gaebe es gar keine impliziten Operationen.
Das wird aber ueblicherweise nicht so gesehen, denn wenn es kein
"implizit" gaebe, waeren die Begriffe "implizit" und "explizit" ueber-
fluessig, da dann alles "explizit" waere, "explizit also keine Bedeu-
tung ausser "gilt immer" haette ...
Post by Rainer Weikusat
In simple assignment (=), the value of the right operand is
converted to the type of the assignment expression and replaces
the value stored in the object designated by the left operand.
Stimmt, Die Typumwandlung muss nicht extra hingeschrieben werden, weil
sie eben *implizit* durchgefuehrt wird.
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Geschmacksache.
"Geschmacksache" ist, ob man solche Redunanzen mag. Aber redundant
bleiben sie.
Das ist kein Widerspruch zum zuvor geschriebenen. Es ist Geschmacksache,
ob man hier eine *explizite* Typumwandlung (in Form eines casts) ergaenzt
Dadurch, dass man einen bestenfalls ueberfluessigen und schlimmstenfalls
falschen Klammerausdruck vor den R-Wert schreibt, ergaenzt man nichts
(weil die 'imaginaere Operation' Bestandteil der Zuweisung ist) ausser
man fuegt einen Fehler hinzu.
Es gibt keine "imaginaeren Operationen", wohl aber in dem von dir genannten
Beispiel eine *implizitwe* Typumwandlung. Wenn man bei impliziten Typumwand-
lungen jeweils warnen wuerde, waere das zwar u.U. manchmal nerbig, wuerde
aber auch bei *falschen* casts warnen, also bei demjenigen, fuer den der
Umgang mit impliziten Konvertierungen fehlertraechtig ist, eine Hilfe dar-
stellen. Ich koennte mich durchaus damit anfreunden, eine Compileroption
anzubieten, die vor impliziten Typkonvertierungen warnt (sie sollte aber
vielleicht nicht per Default enabled sein).

Tschuess,
Juergen Ilse (***@usenet-veerwaltung.de)
Rainer Weikusat
2018-05-28 14:52:05 UTC
Permalink
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Es wird aber explizit hingeschrieben. Das untenstehende
Nein.
Post by Rainer Weikusat
c = i;
... ist eine Zuweisung, die aufgrund der Semantik und der Tatsache der
unterschiedlichen Datentypen von c un i eine Konvertierung erfordert,
die deshalb *IMPLIZIT* i(also ohne dass explizit eine -typumwandlungs-
direktive, sprich ein cast, hingeschrieben wird) durchgefuehrt wird.
Zahlenzuweisungen in C beinhalten immer ggf notwendige
Typkonvertierungen.
Stimmt. Sie beinhalten (bei unterschiedlichen Typen rechts und links vom
Zuweisungsoperator) *zwei* Operationen, von denen eine *implizit* (also
ohne dass sie extra hingeschrieben wird) durchgefuehrt wird.
Eine C-Zuweisung besteht aus zwei Teiloperationen: Konvertierung des
Wertes in den Zieltyp und Speichern des Wertes im Zielobjekt. Das ist
in der C-Norm ausdruecklich so definiert: Eine 'einfache Zuweisung' ohne
Typkonversion gibt es nicht und kann es auch gar nicht geben: Die
einzige Alternative waere, Zuweisungen bei Typunterschieden zu
verbieten.
Post by Juergen Ilse
Post by Rainer Weikusat
Insofern sind sie explizit Bestandteil der
Nach deine Argumentation gaebe es gar keine impliziten Operationen.
Der Text der C-Norm enthaelt die behauptete Unterscheidung nicht.

[...]
Post by Juergen Ilse
Post by Rainer Weikusat
In simple assignment (=), the value of the right operand is
converted to the type of the assignment expression and replaces
the value stored in the object designated by the left operand.
Stimmt, Die Typumwandlung muss nicht extra hingeschrieben werden, weil
sie eben *implizit* durchgefuehrt wird.
Eine Implikation ist etwas, das _nicht_ ausdruecklich benannt wird,
sondern auf dessen Vorhandensein man aufgrund dessen, was ausdruecklich
genannt wurde, schliessen kann. ZB impliziert die Aussage "Angesichts des
gesellschaftlich ueblichen Alkoholkonsum waeren gesetzlich
vorgeschriebene Mindestpreise sinnvoll" dass der Sprecher den 'allgemeinen
Alkoholkonsum' fuer hoeher als wuenschenswert haelt und dass er animmt,
dieser wuerde sich verringern, wenn die Preise stiegen.

Beide Teiloperationen, aus denen eine C-Zuweisung besteht, werden in der
Definition ausdruecklich benannt somit ist keine implizit.
Thomas Koenig
2018-05-28 18:11:34 UTC
Permalink
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Es wird aber explizit hingeschrieben. Das untenstehende
Nein.
Post by Rainer Weikusat
c = i;
... ist eine Zuweisung, die aufgrund der Semantik und der Tatsache der
unterschiedlichen Datentypen von c un i eine Konvertierung erfordert,
die deshalb *IMPLIZIT* i(also ohne dass explizit eine -typumwandlungs-
direktive, sprich ein cast, hingeschrieben wird) durchgefuehrt wird.
Zahlenzuweisungen in C beinhalten immer ggf notwendige
Typkonvertierungen.
Stimmt. Sie beinhalten (bei unterschiedlichen Typen rechts und links vom
Zuweisungsoperator) *zwei* Operationen, von denen eine *implizit* (also
ohne dass sie extra hingeschrieben wird) durchgefuehrt wird.
Eine C-Zuweisung besteht aus zwei Teiloperationen: Konvertierung des
Wertes in den Zieltyp und Speichern des Wertes im Zielobjekt. Das ist
in der C-Norm ausdruecklich so definiert: Eine 'einfache Zuweisung' ohne
Typkonversion gibt es nicht und kann es auch gar nicht geben: Die
einzige Alternative waere, Zuweisungen bei Typunterschieden zu
verbieten.
Naja, anscheinend hast du eine andere Bedeutung für das Wort "implizit"
als andere Leute.

Angenommen, ich habe ein Funktion

void foo(int, ...);

und rufe sie auf mit

int i;
i = 42;
foo (1, (float) i);

ist da irgendwas implizites drin, oder sind da zwei explizite
Umwandlungen?

Just curious...
Rainer Weikusat
2018-05-28 19:07:59 UTC
Permalink
Post by Thomas Koenig
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Rainer Weikusat
Es wird aber explizit hingeschrieben. Das untenstehende
Nein.
Post by Rainer Weikusat
c = i;
... ist eine Zuweisung, die aufgrund der Semantik und der Tatsache der
unterschiedlichen Datentypen von c un i eine Konvertierung erfordert,
die deshalb *IMPLIZIT* i(also ohne dass explizit eine -typumwandlungs-
direktive, sprich ein cast, hingeschrieben wird) durchgefuehrt wird.
Zahlenzuweisungen in C beinhalten immer ggf notwendige
Typkonvertierungen.
Stimmt. Sie beinhalten (bei unterschiedlichen Typen rechts und links vom
Zuweisungsoperator) *zwei* Operationen, von denen eine *implizit* (also
ohne dass sie extra hingeschrieben wird) durchgefuehrt wird.
Eine C-Zuweisung besteht aus zwei Teiloperationen: Konvertierung des
Wertes in den Zieltyp und Speichern des Wertes im Zielobjekt. Das ist
in der C-Norm ausdruecklich so definiert: Eine 'einfache Zuweisung' ohne
Typkonversion gibt es nicht und kann es auch gar nicht geben: Die
einzige Alternative waere, Zuweisungen bei Typunterschieden zu
verbieten.
Naja, anscheinend hast du eine andere Bedeutung für das Wort "implizit"
als andere Leute.
Ich verstehe den scheinbaren Gegensatz hier naemlich "mit und ohne
cast". Allerdings halte ich diese Ansicht fuer falsch: C-Zuweisungen
machen Typumwandlungen. Das ist meiner Ansicht nach
selbstverstaendlicher, fester Bestandteil ihrer Funktion. Ich benutze zB
auch Konstrukte wie

int tuwas(void *arg)
{
struct etwas *e;

e = arg;

gefolgt von Code, der mit etwas etwas macht. Sinn dieser Zuweisung ist
primaer die Umwandlung des void * in einen 'eigentlichen Typ'.
Post by Thomas Koenig
Angenommen, ich habe ein Funktion
void foo(int, ...);
und rufe sie auf mit
int i;
i = 42;
foo (1, (float) i);
ist da irgendwas implizites drin, oder sind da zwei explizite
Umwandlungen?
Der Typ von 1 ist int, da wird nichts umgewandelt. Das zweite benutzt
einen Typwandlungsoperator.
Thomas Koenig
2018-05-28 20:07:47 UTC
Permalink
Post by Rainer Weikusat
Post by Thomas Koenig
Angenommen, ich habe ein Funktion
void foo(int, ...);
und rufe sie auf mit
int i;
i = 42;
foo (1, (float) i);
ist da irgendwas implizites drin, oder sind da zwei explizite
Umwandlungen?
Der Typ von 1 ist int, da wird nichts umgewandelt. Das zweite benutzt
einen Typwandlungsoperator.
... und wird noch mal gewandelt, nach double. Ist das implizit genug?
:-)
Claus Reibenstein
2018-05-27 16:36:14 UTC
Permalink
Post by Rainer Weikusat
Auf der Basis derselben Logik koennte man auch eine "Subtraction
operator detected, sure you didn't mean multiplication?" ausgeben
lassen
Netter Versuch. Auf dieses Niveau will und werde ich mich aber nicht
begeben.

Gruß
Claus
Rainer Weikusat
2018-05-27 17:36:08 UTC
Permalink
Post by Claus Reibenstein
Post by Rainer Weikusat
Auf der Basis derselben Logik koennte man auch eine "Subtraction
operator detected, sure you didn't mean multiplication?" ausgeben
lassen
Netter Versuch. Auf dieses Niveau will und werde ich mich aber nicht
begeben.
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt- waehrend obiges eine
unbegruendete, abfaellige Bemerkung ueber mich darstellt.

Bleibe jeder bei seinem Niveau.
Оlе Ѕtrеісhеr
2018-05-27 18:07:14 UTC
Permalink
Post by Rainer Weikusat
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt
Ein Grund könnte aus der Auswertung typischer Bugs folgen: Wenn ein
Fehler regelmäßig wieder gemacht wird, ist es ein guter Grund, eine
Warnung einzubauen.

Zumindest meine Erfahrungen mit fremde Programmen ist durchaus, dass
"unerwartete" Konvertierungen eine potentielle Fehlerquelle sind;
entsprechende Warnungen verkürzen die Zeit zum Debuggen ungemein.

Nimmt man Deine Argumentation ernst, könnte man auch auf alle Warnungen
verzichten -- alles, was kein Fehler ist, kann ja auch explizit so
gedacht sein.

Ich sehe auch nicht, dass explizite Typwandlungen den Code schlechter
lesbar machen. Gerade wenn der Typ von foo oder bar nicht unmittelbar
offensichtlich sind, erscheint mir ein

foo = (unsigned short)bar;

sinnvoll, um lokal zu verstehen, dass hier eine Typumwandlung erfolgt.

Ole
Rainer Weikusat
2018-05-27 20:31:33 UTC
Permalink
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt
Ein Grund könnte aus der Auswertung typischer Bugs folgen: Wenn ein
Fehler regelmäßig wieder gemacht wird, ist es ein guter Grund, eine
Warnung einzubauen.
Man kann aber keine "typischen Bugs" auswerten. Man kann Statistiken
ueber Fehler in irgendwelchen Code-Mengen anlegen. Damit bekommt man
historische Information darueber, was die Autoren dieses Codes zum
fraglichen Zeitpunkt wie haeufig falsch gemacht haben. Weiteren
Aussagewert hat das keinen.

[...]
Post by Оlе Ѕtrеісhеr
Nimmt man Deine Argumentation ernst, könnte man auch auf alle Warnungen
verzichten -- alles, was kein Fehler ist, kann ja auch explizit so
gedacht sein.
Viele Warnungen sind in der Tat vollkommen ueberfluessig wenn nicht
sogar schaedlich. Das muss man sich aber im Einzelfall ansehen.
Post by Оlе Ѕtrеісhеr
Ich sehe auch nicht, dass explizite Typwandlungen den Code schlechter
lesbar machen.
Je mehr Text, desto mehr Arbeit ist noetig, um ihn zu lesen, und je mehr
man verstehen muss, desto mehr kann man falsch verstehen.
Post by Оlе Ѕtrеісhеr
Gerade wenn der Typ von foo oder bar nicht unmittelbar
offensichtlich sind, erscheint mir ein
foo = (unsigned short)bar;
sinnvoll, um lokal zu verstehen, dass hier eine Typumwandlung erfolgt.
---------
##include <stdio.h>

int main(void)
{
int i = -1;
short c;

c = (unsigned char)i;
printf("%d\n", c);

return 0;
}
---------

Ist obiges ein Voodoo-cast, den jemand versehentlich oder nachlaessig
falsch gemacht hat, oder sollte das passieren?
Оlе Ѕtrеісhеr
2018-05-28 00:46:34 UTC
Permalink
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt
Ein Grund könnte aus der Auswertung typischer Bugs folgen: Wenn ein
Fehler regelmäßig wieder gemacht wird, ist es ein guter Grund, eine
Warnung einzubauen.
Man kann aber keine "typischen Bugs" auswerten. Man kann Statistiken
ueber Fehler in irgendwelchen Code-Mengen anlegen. Damit bekommt man
historische Information darueber, was die Autoren dieses Codes zum
fraglichen Zeitpunkt wie haeufig falsch gemacht haben. Weiteren
Aussagewert hat das keinen.
Das ist also schonmal sehr hilfreich, wenn man historischen Code
wartet, womit wir schon einmal einen Anwendungsfall haben.

Dazu kommt, dass man "historisch" durchaus auch als "in den letzten paar
Jahren vor der Einführung einer Warnung" verstehen kann. Damit liefern
neue Warnungen durchaus auch Hilfestellungen bei der Wartung (relativ)
aktuellen Codes.
Post by Rainer Weikusat
[...]
Post by Оlе Ѕtrеісhеr
Nimmt man Deine Argumentation ernst, könnte man auch auf alle Warnungen
verzichten -- alles, was kein Fehler ist, kann ja auch explizit so
gedacht sein.
Viele Warnungen sind in der Tat vollkommen ueberfluessig wenn nicht
sogar schaedlich. Das muss man sich aber im Einzelfall ansehen.
Oder man kann sie auch einfach abschalten. Sogar ziemlich selektiv.
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Ich sehe auch nicht, dass explizite Typwandlungen den Code schlechter
lesbar machen.
Je mehr Text, desto mehr Arbeit ist noetig, um ihn zu lesen, und je mehr
man verstehen muss, desto mehr kann man falsch verstehen.
Steile These. Und sie ist auch nicht logisch konsistent: Natürlich muss
man mehr lesen. Aber man muss nicht "mehr" verstehen, sondern man
bekommt die zum Verständnis erforderliche Information lokal angeboten.

Und Typumwandlungen sind normalerweise relativ selten sind im Vergleich
zu normalen Zuweisungen. Ihre explizite Angabe vergrößert daher nicht
signifikant den Code.
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Gerade wenn der Typ von foo oder bar nicht unmittelbar
offensichtlich sind, erscheint mir ein
foo = (unsigned short)bar;
sinnvoll, um lokal zu verstehen, dass hier eine Typumwandlung erfolgt.
---------
##include <stdio.h>
int main(void)
{
int i = -1;
short c;
c = (unsigned char)i;
printf("%d\n", c);
return 0;
}
---------
Ist obiges ein Voodoo-cast, den jemand versehentlich oder nachlaessig
falsch gemacht hat, oder sollte das passieren?
Dazu muss man den Kontext wissen, den Du leider nicht angegeben
hast. Davon abgesehen, ist ein "c = (unsichned char)i" wohl nicht so
schnell "versehentlich" geschrieben wie ein "c = i". Im ersten Fall
würde ich nämlich davon ausgehen, dass man sich zumindest einige
Gedanken über den Zieltypen gemacht hat. Und typisch sind (zumindest bei
mir) eher Fälle wie

#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif

void kunkle(int a) {
voobar = a;
}

int lenku(void) {
return voobar;
}

wo man ohne genauere Untersuchung aller Includes nicht versteht, was
passiert. Und da hilft es beim Debugging durchaus, wenn man weiß, ob

kunkle(-123456789);
if (lenku() == -123456789) {
printf("Yea\n");
}

wirklich was ausdrucken wird. Ein guter Anhaltspunkt dafür ist eine
Compilerwarnung.

Meine Erfahrung hier ist, dass ich *fremden* Code, der mit expliziten
Typumwandlungen arbeitet, im allgemeinen besser und schneller verstehe
also solchen ohne. Daher hilft mir eine Warnung, die *andere* Leute dazu
bringt, explizite Typumwandlungen einzubauen. Da ich mich selbst nicht
für einen extraordinär guten Programmierer halte, wird es umgekehrt
sicher auch so sein.

Ole
Helmut Schellong
2018-05-28 11:44:02 UTC
Permalink
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Je mehr Text, desto mehr Arbeit ist noetig, um ihn zu lesen, und je mehr
man verstehen muss, desto mehr kann man falsch verstehen.
Steile These. Und sie ist auch nicht logisch konsistent: Natürlich muss
man mehr lesen. Aber man muss nicht "mehr" verstehen, sondern man
bekommt die zum Verständnis erforderliche Information lokal angeboten.
Es ist aber genau so:
Je mehr 'Stoff' vorhanden ist, desto höher die
Wahrscheinlichkeit für Fehler.
Sogar Kommentare gehören dazu, wenn ein Wust davon da ist!

Das gilt überall!
Bei Elektronischen Schaltungen steigt die Fehlerwahrscheinlichkeit
mit der Anzahl der Lötstellen, der Anschlußpinne, Leiterbahnen,
Bauelemente, ...

Eine Firma hatte mal einen Ada-Compiler für 120000 DM
voller Stolz präsentiert.
Der hat über 20 MegaByte Umfang und enthält ungeheuer
viel Sicherheits-Algorithmen...

Kommentar von einer Sicherheitsspezialistin:
Dieser Compiler ist genau wegen seines enormen Umfangs
beträchtlich unsicherer als 10-fach kleinere Compiler!

Diese Betrachtung ist fortsetzbar.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Оlе Ѕtrеісhеr
2018-05-28 13:45:18 UTC
Permalink
Post by Helmut Schellong
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Je mehr Text, desto mehr Arbeit ist noetig, um ihn zu lesen, und je mehr
man verstehen muss, desto mehr kann man falsch verstehen.
Steile These. Und sie ist auch nicht logisch konsistent: Natürlich muss
man mehr lesen. Aber man muss nicht "mehr" verstehen, sondern man
bekommt die zum Verständnis erforderliche Information lokal angeboten.
Je mehr 'Stoff' vorhanden ist, desto höher die
Wahrscheinlichkeit für Fehler.
Es geht hier aber nicht um die Gesamtzahl der Fehler, sondern um die
Zahl der Fehler, die nicht mit Compilerhilfe entdeckt werden. Und da ist
explizit oft genug tatsächlich weniger fehlerträchtig als implizit.
Rainer Weikusat
2018-05-28 17:39:58 UTC
Permalink
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt
Ein Grund könnte aus der Auswertung typischer Bugs folgen: Wenn ein
Fehler regelmäßig wieder gemacht wird, ist es ein guter Grund, eine
Warnung einzubauen.
Man kann aber keine "typischen Bugs" auswerten. Man kann Statistiken
ueber Fehler in irgendwelchen Code-Mengen anlegen. Damit bekommt man
historische Information darueber, was die Autoren dieses Codes zum
fraglichen Zeitpunkt wie haeufig falsch gemacht haben. Weiteren
Aussagewert hat das keinen.
Das ist also schonmal sehr hilfreich, wenn man historischen Code
wartet, womit wir schon einmal einen Anwendungsfall haben.
Falls jemand eine automatische/ zuverlaessige Methode haette, alle
Fehler in irgendwelchem 'historischen Code', den Du aus sonstwas fuer
Gruenden benutzt, zu finden, waare das offensichtlich hilfreich _fuer
Dich_ (sowie eventuelle andere Nutzer).

Das sagt aber per se nichts ueber anderen Code, den ich benutze (oder
sonstjemand) aus.

[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Ich sehe auch nicht, dass explizite Typwandlungen den Code schlechter
lesbar machen.
Je mehr Text, desto mehr Arbeit ist noetig, um ihn zu lesen, und je mehr
man verstehen muss, desto mehr kann man falsch verstehen.
Steile These. Und sie ist auch nicht logisch konsistent: Natürlich muss
man mehr lesen. Aber man muss nicht "mehr" verstehen, sondern man
bekommt die zum Verständnis erforderliche Information lokal angeboten.
Wenn man mehr Text lesen muss, muss man auch mehr Text verstehen. Oder
zumindestens muesste man :-).
Post by Оlе Ѕtrеісhеr
Und Typumwandlungen sind normalerweise relativ selten sind im Vergleich
zu normalen Zuweisungen. Ihre explizite Angabe vergrößert daher nicht
signifikant den Code.
Eine Ameise in der Wohnung ist keine signifikante Belaestigung. Wie
kommt es bloss, dass eine Ameisenstrasse vom Garten zur Speisekammer
eine signifikante Belaestigung ist, obwohl sie duch nur aus Ameisen
besteht, die selber keine sind?

Antwort: Die Masse machts.

[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
---------
##include <stdio.h>
int main(void)
{
int i = -1;
short c;
c = (unsigned char)i;
printf("%d\n", c);
return 0;
}
---------
Ist obiges ein Voodoo-cast, den jemand versehentlich oder nachlaessig
falsch gemacht hat, oder sollte das passieren?
Dazu muss man den Kontext wissen, den Du leider nicht angegeben
hast. Davon abgesehen, ist ein "c = (unsichned char)i" wohl nicht so
schnell "versehentlich" geschrieben wie ein "c = i".
Beide Zeilen lassen sich gleichschnell von einem Ort A zu einem Ort B
kopieren. Und zusaetzlicher Code, der kein offensichtliches
Fehlverhalten verursacht, wird grundsaetzlich nicht geaendert.
Оlе Ѕtrеісhеr
2018-05-28 18:15:07 UTC
Permalink
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt
Ein Grund könnte aus der Auswertung typischer Bugs folgen: Wenn ein
Fehler regelmäßig wieder gemacht wird, ist es ein guter Grund, eine
Warnung einzubauen.
Man kann aber keine "typischen Bugs" auswerten. Man kann Statistiken
ueber Fehler in irgendwelchen Code-Mengen anlegen. Damit bekommt man
historische Information darueber, was die Autoren dieses Codes zum
fraglichen Zeitpunkt wie haeufig falsch gemacht haben. Weiteren
Aussagewert hat das keinen.
Das ist also schonmal sehr hilfreich, wenn man historischen Code
wartet, womit wir schon einmal einen Anwendungsfall haben.
Falls jemand eine automatische/ zuverlaessige Methode haette, alle
Fehler in irgendwelchem 'historischen Code', den Du aus sonstwas fuer
Gruenden benutzt, zu finden, waare das offensichtlich hilfreich _fuer
Dich_ (sowie eventuelle andere Nutzer).
Das sagt aber per se nichts ueber anderen Code, den ich benutze (oder
sonstjemand) aus.
Ich verwende sicher nicht ganz besonderen Code, der aufgrund seiner
spezifischen Programmierung ausgewählt wurde. Das gibt Anlass zur
Vermutung, dass mein Code nicht ganz untypisch ist, das Problem also
anderswo ebenso auftritt.

Und wenn er bei Dir nicht auftritt, dann kannst Du die Warnung doch
einfach abschalten, oder?
Post by Rainer Weikusat
[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Ich sehe auch nicht, dass explizite Typwandlungen den Code schlechter
lesbar machen.
Je mehr Text, desto mehr Arbeit ist noetig, um ihn zu lesen, und je mehr
man verstehen muss, desto mehr kann man falsch verstehen.
Steile These. Und sie ist auch nicht logisch konsistent: Natürlich muss
man mehr lesen. Aber man muss nicht "mehr" verstehen, sondern man
bekommt die zum Verständnis erforderliche Information lokal angeboten.
Wenn man mehr Text lesen muss, muss man auch mehr Text verstehen. Oder
zumindestens muesste man :-).
So what? Da die Typumwandlung i.allg. redundant ist, bleibt die Menge
des zu verstehenden Inhalts konstant. Man muss also nicht *mehr* verstehen.

Mit dem Unterschied, dass man die relevante Information lokal bekommt,
ohne sie erst suchen zu müssen (ein Argument, dass Du beharrlich
ignorierst).
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Und Typumwandlungen sind normalerweise relativ selten sind im Vergleich
zu normalen Zuweisungen. Ihre explizite Angabe vergrößert daher nicht
signifikant den Code.
Eine Ameise in der Wohnung ist keine signifikante Belaestigung. Wie
kommt es bloss, dass eine Ameisenstrasse vom Garten zur Speisekammer
eine signifikante Belaestigung ist, obwohl sie duch nur aus Ameisen
besteht, die selber keine sind?
Antwort: Die Masse machts.
Dass es sich bei den durch Warnungen induzierten Codeänderungen um eine
in der Summe signifikante Vergrößerung der Codesize handelt, hätte ich
dann doch gerne mal belegt.
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
##include <stdio.h>
int main(void)
{
int i = -1;
short c;
c = (unsigned char)i;
printf("%d\n", c);
return 0;
}
---------
Ist obiges ein Voodoo-cast, den jemand versehentlich oder nachlaessig
falsch gemacht hat, oder sollte das passieren?
Dazu muss man den Kontext wissen, den Du leider nicht angegeben
hast. Davon abgesehen, ist ein "c = (unsichned char)i" wohl nicht so
schnell "versehentlich" geschrieben wie ein "c = i".
Beide Zeilen lassen sich gleichschnell von einem Ort A zu einem Ort B
kopieren. Und zusaetzlicher Code, der kein offensichtliches
Fehlverhalten verursacht, wird grundsaetzlich nicht geaendert.
Ich pflege meine Programme nicht zu kopieren, sondern selbst zu
schreiben.

Mein Beispiel ist Dir übrigens irgendwie verlorengegangen...

#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif

void kunkle(int a) {
voobar = a;
}

int lenku(void) {
return voobar;
}

Die Zuweisung kannst Du da auch sicher ohne weiteres von A nach B
kopieren. Ob sie dann noch so funktioniert, wie sie soll, bleibt
fraglich.
Rainer Weikusat
2018-05-29 17:36:38 UTC
Permalink
[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Man kann aber keine "typischen Bugs" auswerten. Man kann Statistiken
ueber Fehler in irgendwelchen Code-Mengen anlegen. Damit bekommt man
historische Information darueber, was die Autoren dieses Codes zum
fraglichen Zeitpunkt wie haeufig falsch gemacht haben.
[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Das ist also schonmal sehr hilfreich, wenn man historischen Code
wartet, womit wir schon einmal einen Anwendungsfall haben.
Falls jemand eine automatische/ zuverlaessige Methode haette, alle
Fehler in irgendwelchem 'historischen Code', den Du aus sonstwas fuer
Gruenden benutzt, zu finden, waare das offensichtlich hilfreich _fuer
Dich_ (sowie eventuelle andere Nutzer).
Das sagt aber per se nichts ueber anderen Code, den ich benutze (oder
sonstjemand) aus.
Ich verwende sicher nicht ganz besonderen Code, der aufgrund seiner
spezifischen Programmierung ausgewählt wurde. Das gibt Anlass zur
Vermutung, dass mein Code nicht ganz untypisch ist, das Problem also
anderswo ebenso auftritt.
Jeglicher Code, den Du (oder sonstwer) verwendet, ist in jedem Fall ein
sehr spezieller und sehr kleiner Teil der Menge von 'Code' die auf
dieser Welt bereits existiert und in Zukunft existieren wird. Einen
sachlichen Anlass, zu vermuten, das das, was man zufaellig kennt, ein
repraesentatives Beispiel ist, gibt es nicht. Man sollte vielmehr das
Gegenteil annehmen oder vielleicht besser ueberhaupt gar nichts. Wissen
laesst sich nicht durch Spekulation gewinnen.

[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Ich sehe auch nicht, dass explizite Typwandlungen den Code schlechter
lesbar machen.
Je mehr Text, desto mehr Arbeit ist noetig, um ihn zu lesen, und je mehr
man verstehen muss, desto mehr kann man falsch verstehen.
Steile These. Und sie ist auch nicht logisch konsistent: Natürlich muss
man mehr lesen. Aber man muss nicht "mehr" verstehen, sondern man
bekommt die zum Verständnis erforderliche Information lokal angeboten.
Wenn man mehr Text lesen muss, muss man auch mehr Text verstehen. Oder
zumindestens muesste man :-).
So what? Da die Typumwandlung i.allg. redundant ist, bleibt die Menge
des zu verstehenden Inhalts konstant. Man muss also nicht *mehr* verstehen.
Inhalt ist das, was man bekomment, nachdem eine Nachricht dekodiert
wurde. Falls sich nach Dekodierung, dh, nach 'verstehen' der Nachricht
in ihre gewaehlten Repraesentation heraustellt, dass 80% Wiederholungen
von "Das hier haette nicht dekodiert werden muessen, wenn wir es nicht
mit dem inhaltstragenden Teilen zusammengemengt haetten" waren, hat man
einen Haufen Zeit verschwendet.
Post by Оlе Ѕtrеісhеr
Mit dem Unterschied, dass man die relevante Information lokal bekommt,
ohne sie erst suchen zu müssen (ein Argument, dass Du beharrlich
ignorierst).
Ich halte technisch sinnfreie Wiederholung eines Typs in prinzipiell
unbegrenzten Zahl von Programmzeilen nicht nur fuer 'nicht relevant'
sondern ausserdem fuer schaedlich: Zu dem bereits im letzten Absatz
erwaehnten kommt noch hinzu, dass man im Falle einer Typaenderungen
einen potentiell massive Menge von redundanten Casts aendern muesste.
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Und Typumwandlungen sind normalerweise relativ selten sind im Vergleich
zu normalen Zuweisungen. Ihre explizite Angabe vergrößert daher nicht
signifikant den Code.
Eine Ameise in der Wohnung ist keine signifikante Belaestigung. Wie
kommt es bloss, dass eine Ameisenstrasse vom Garten zur Speisekammer
eine signifikante Belaestigung ist, obwohl sie duch nur aus Ameisen
besteht, die selber keine sind?
Antwort: Die Masse machts.
Dass es sich bei den durch Warnungen induzierten Codeänderungen um eine
in der Summe signifikante Vergrößerung der Codesize handelt, hätte ich
dann doch gerne mal belegt.
Versuchen wir es mit einem anderen Beispiel: Wenn jemand Waren im Wert
von 1DM klaut, schaedigt er niemanden signifikant.

Sollte man das also erlauben oder sogar gutheissen?
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
##include <stdio.h>
int main(void)
{
int i = -1;
short c;
c = (unsigned char)i;
printf("%d\n", c);
return 0;
}
---------
Ist obiges ein Voodoo-cast, den jemand versehentlich oder nachlaessig
falsch gemacht hat, oder sollte das passieren?
Dazu muss man den Kontext wissen, den Du leider nicht angegeben
hast. Davon abgesehen, ist ein "c = (unsichned char)i" wohl nicht so
schnell "versehentlich" geschrieben wie ein "c = i".
Beide Zeilen lassen sich gleichschnell von einem Ort A zu einem Ort B
kopieren. Und zusaetzlicher Code, der kein offensichtliches
Fehlverhalten verursacht, wird grundsaetzlich nicht geaendert.
Ich pflege meine Programme nicht zu kopieren, sondern selbst zu
schreiben.
Andere Leute (und zwar ziemliche Massen davon) pflegen existierenden Code
zu kopieren und nur insoweit unbedingt erforderlich zu aendern. Falls
das ein Problem ist, mit dem Du Dich noch nicht auseinandersetzen
musstest, moechte ich das "beneidenswert" nennen, aber sogar in einem
"peer reviewten" Grossprojekt wie Linux findet man Code, der mit samt
Kommentaren woandershin kopiert wurde und woran in Folge nahezu alles
ausser dem Kommentar geaendert wurde (genaue Fundstelle habe ich
vergessen, war "irgendwas-ARM", IXP425 denke ich).
Post by Оlе Ѕtrеісhеr
Mein Beispiel ist Dir übrigens irgendwie verlorengegangen...
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
Die Zuweisung kannst Du da auch sicher ohne weiteres von A nach B
kopieren. Ob sie dann noch so funktioniert, wie sie soll, bleibt
fraglich.
Es gibt Gruende, warum solche Verwendung von Variablen mit externer
Bindung fuer schlechten Stil gehalten wird ...
Оlе Ѕtrеісhеr
2018-05-29 18:02:25 UTC
Permalink
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
Die Zuweisung kannst Du da auch sicher ohne weiteres von A nach B
kopieren. Ob sie dann noch so funktioniert, wie sie soll, bleibt
fraglich.
Es gibt Gruende, warum solche Verwendung von Variablen mit externer
Bindung fuer schlechten Stil gehalten wird ...
... nur hilft lamentieren da eben nicht weiter. Solcher Code existiert,
wird verwendent, und zwar durchaus in Mengen, und in da hilft eine
Compilerwarnung vor impliziten Codewandlungen durchaus beim Review und
beim Debugging.

Nochmal: Es zwingt Dich ja keiner, solche Warnungen anzuschalten. Wenn
Dein Code so gut geschrieben ist, dass Typumwandlungen unmittelbar
erkennbar sind, dann brauchst Du sie sicher nicht.

Allerdings ist es nicht sinnvoll, sich bei der Beurteilung der
Lesbarkeit des eigenen Codes nur auf seine eigene Meinung zu
verlassen.

Ole
Rainer Weikusat
2018-05-30 14:41:08 UTC
Permalink
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
Die Zuweisung kannst Du da auch sicher ohne weiteres von A nach B
kopieren. Ob sie dann noch so funktioniert, wie sie soll, bleibt
fraglich.
Es gibt Gruende, warum solche Verwendung von Variablen mit externer
Bindung fuer schlechten Stil gehalten wird ...
... nur hilft lamentieren da eben nicht weiter. Solcher Code existiert,
wird verwendent, und zwar durchaus in Mengen, und in da hilft eine
Compilerwarnung vor impliziten Codewandlungen durchaus beim Review und
beim Debugging.
Das da oben ist ein kuenstliches Beispiel, dass Du Dir aus einem fuer
mich unersichtlichen Grund ausgedacht hast. Meiner Ansicht nach
demonstriert es nicht ausser, dass Du imstande bist, Code zu schreiben,
den ich ohnen zwingenden Grund fuer nichts benutzen wollen wuerde,
allerdings habe ich den Versuch gemacht, so taktvoll zu sein, das nicht
ausdruecklich zu schreiben. War wohl nix.
Оlе Ѕtrеісhеr
2018-05-30 15:19:31 UTC
Permalink
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
Die Zuweisung kannst Du da auch sicher ohne weiteres von A nach B
kopieren. Ob sie dann noch so funktioniert, wie sie soll, bleibt
fraglich.
Es gibt Gruende, warum solche Verwendung von Variablen mit externer
Bindung fuer schlechten Stil gehalten wird ...
... nur hilft lamentieren da eben nicht weiter. Solcher Code existiert,
wird verwendent, und zwar durchaus in Mengen, und in da hilft eine
Compilerwarnung vor impliziten Codewandlungen durchaus beim Review und
beim Debugging.
Das da oben ist ein kuenstliches Beispiel, dass Du Dir aus einem fuer
mich unersichtlichen Grund ausgedacht hast.
Das Beispiel ist nicht ausgedacht, sondern entstammt im Wesentlichen dem
Quellcode von IRAF (genaugenommen dem "ecl" Paket darin).

https://github.com/iraf/iraf-v216/blob/master/pkg/ecl/main.c#L310

Frage: Gehen bei dieser Zuweisung signifikante bits verloren?
Post by Rainer Weikusat
Meiner Ansicht nach demonstriert es nicht ausser, dass Du imstande
bist, Code zu schreiben, den ich ohnen zwingenden Grund fuer nichts
benutzen wollen wuerde,
Die Frage, ob man einen 30 Jahre alten Code "benutzen wollen würde"
hängt nicht nur von der Codequalität ab, sondern auch von den
Anforderungen der Anwender, die dieses Programm seit 30 Jahren verwenden
und dies gern (in geringem Umfang) noch weiter tun möchten.

Ole
Rainer Weikusat
2018-05-30 18:11:09 UTC
Permalink
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
Die Zuweisung kannst Du da auch sicher ohne weiteres von A nach B
kopieren. Ob sie dann noch so funktioniert, wie sie soll, bleibt
fraglich.
Es gibt Gruende, warum solche Verwendung von Variablen mit externer
Bindung fuer schlechten Stil gehalten wird ...
... nur hilft lamentieren da eben nicht weiter. Solcher Code existiert,
wird verwendent, und zwar durchaus in Mengen, und in da hilft eine
Compilerwarnung vor impliziten Codewandlungen durchaus beim Review und
beim Debugging.
Das da oben ist ein kuenstliches Beispiel, dass Du Dir aus einem fuer
mich unersichtlichen Grund ausgedacht hast.
Das Beispiel ist nicht ausgedacht, sondern entstammt im Wesentlichen dem
Quellcode von IRAF (genaugenommen dem "ecl" Paket darin).
https://github.com/iraf/iraf-v216/blob/master/pkg/ecl/main.c#L310
Die referenzierte Zeile ist

currentask->t_topcs = topcs;

Inwiefern das obigem aehneln soll, verstehe ich nicht.
Post by Оlе Ѕtrеісhеr
Frage: Gehen bei dieser Zuweisung signifikante bits verloren?
Um diese Frage beantworten zu koennen, muesste man den nicht angegebenen
Typ der Variablen kennen. Ferner muesste eine Datenflussanalyse ergeben,
das reale Werte von a tatsaechlich mehr Bits haben, als in voobar zur
Verfuegung stehen und es muesste auch noch wenigstens eine Codestelle
geben, deren Verhalten fehlerhaft ist, weil die entsprechenden Bits
unter den Tisch fielen.

Eine "Zieltyp kuerzer als Quelltyp!"-Warnung hilft hier direkt nichts.
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Meiner Ansicht nach demonstriert es nicht ausser, dass Du imstande
bist, Code zu schreiben, den ich ohnen zwingenden Grund fuer nichts
benutzen wollen wuerde,
Die Frage, ob man einen 30 Jahre alten Code "benutzen wollen würde"
hängt nicht nur von der Codequalität ab, sondern auch von den
Anforderungen der Anwender, die dieses Programm seit 30 Jahren verwenden
und dies gern (in geringem Umfang) noch weiter tun möchten.
Deswegen hatte ich "ohne zwingenden Grund" geschrieben.
Оlе Ѕtrеісhеr
2018-05-30 19:04:48 UTC
Permalink
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
Die Zuweisung kannst Du da auch sicher ohne weiteres von A nach B
kopieren. Ob sie dann noch so funktioniert, wie sie soll, bleibt
fraglich.
Es gibt Gruende, warum solche Verwendung von Variablen mit externer
Bindung fuer schlechten Stil gehalten wird ...
... nur hilft lamentieren da eben nicht weiter. Solcher Code existiert,
wird verwendent, und zwar durchaus in Mengen, und in da hilft eine
Compilerwarnung vor impliziten Codewandlungen durchaus beim Review und
beim Debugging.
Das da oben ist ein kuenstliches Beispiel, dass Du Dir aus einem fuer
mich unersichtlichen Grund ausgedacht hast.
Das Beispiel ist nicht ausgedacht, sondern entstammt im Wesentlichen dem
Quellcode von IRAF (genaugenommen dem "ecl" Paket darin).
https://github.com/iraf/iraf-v216/blob/master/pkg/ecl/main.c#L310
Die referenzierte Zeile ist
currentask->t_topcs = topcs;
Inwiefern das obigem aehneln soll, verstehe ich nicht.
Der Unterschied ist lediglich, dass die Zielvariable Teil einer Struktur
ist. Welchen Typ sie hat, ist aus dem Code hier nicht unmittelbar
ersichtlich. Du wirst mir zubilligen, dass ich das Beispiel auf das
Wesentliche verkürze; und dass t_topcs Teil einer Struktur ist, ist für
das Problem unwesentlich.

Dass ich daraus einen Getter und einen Setter gemacht habe, geschah nur,
um das Problem prägnanter zu machen.

War das jetzt verständlich genug?
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Frage: Gehen bei dieser Zuweisung signifikante bits verloren?
Um diese Frage beantworten zu koennen, muesste man den nicht angegebenen
Typ der Variablen kennen. Ferner muesste eine Datenflussanalyse ergeben,
das reale Werte von a tatsaechlich mehr Bits haben, als in voobar zur
Verfuegung stehen und es muesste auch noch wenigstens eine Codestelle
geben, deren Verhalten fehlerhaft ist, weil die entsprechenden Bits
unter den Tisch fielen.
Eine "Zieltyp kuerzer als Quelltyp!"-Warnung hilft hier direkt nichts.
Doch. Sie hilft nämlich zu erkennen, dass es hier ein Problem geben
könnte und man sich die Stelle genauer ansehen müsste. Wenn ich in einem
Problem feststelle, dass irgendwo leading bits verloren gehen, dann
hilft es in einem >>100kLines Projekt ungemein, wenn der Compiler solche
Stellen findet. Wenn man dann feststellt, dass die Typumwandlung hier
korrekt erfolgt, dann kann man das damit dokumentieren, dass man die
Typumwandlung explizit angibt und damit die Warnung abschaltet.
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Meiner Ansicht nach demonstriert es nicht ausser, dass Du imstande
bist, Code zu schreiben, den ich ohnen zwingenden Grund fuer nichts
benutzen wollen wuerde,
Die Frage, ob man einen 30 Jahre alten Code "benutzen wollen würde"
hängt nicht nur von der Codequalität ab, sondern auch von den
Anforderungen der Anwender, die dieses Programm seit 30 Jahren verwenden
und dies gern (in geringem Umfang) noch weiter tun möchten.
Deswegen hatte ich "ohne zwingenden Grund" geschrieben.
"Zwingend" ist gar nix. Und wenn es keinen Grund gäbe, würde ich es
nicht verwenden.

Ole
Rainer Weikusat
2018-05-30 19:16:31 UTC
Permalink
ole-usenet-***@gmx.net (Оlе Ѕtrеісhеr) writes:

[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Оlе Ѕtrеісhеr
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Das Beispiel ist nicht ausgedacht, sondern entstammt im Wesentlichen dem
Quellcode von IRAF (genaugenommen dem "ecl" Paket darin).
https://github.com/iraf/iraf-v216/blob/master/pkg/ecl/main.c#L310
Die referenzierte Zeile ist
currentask->t_topcs = topcs;
Inwiefern das obigem aehneln soll, verstehe ich nicht.
Der Unterschied ist lediglich, dass die Zielvariable Teil einer Struktur
ist. Welchen Typ sie hat, ist aus dem Code hier nicht unmittelbar
ersichtlich. Du wirst mir zubilligen, dass ich das Beispiel auf das
Wesentliche verkürze; und dass t_topcs Teil einer Struktur ist, ist für
das Problem unwesentlich.
Dass ich daraus einen Getter und einen Setter gemacht habe, geschah nur,
um das Problem prägnanter zu machen.
War das jetzt verständlich genug?
Es soll ihm also nicht aehneln.
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Frage: Gehen bei dieser Zuweisung signifikante bits verloren?
Um diese Frage beantworten zu koennen, muesste man den nicht angegebenen
Typ der Variablen kennen. Ferner muesste eine Datenflussanalyse ergeben,
das reale Werte von a tatsaechlich mehr Bits haben, als in voobar zur
Verfuegung stehen und es muesste auch noch wenigstens eine Codestelle
geben, deren Verhalten fehlerhaft ist, weil die entsprechenden Bits
unter den Tisch fielen.
Eine "Zieltyp kuerzer als Quelltyp!"-Warnung hilft hier direkt nichts.
Doch. Sie hilft nämlich zu erkennen, dass es hier ein Problem geben
könnte und man sich die Stelle genauer ansehen müsste.
Sie 'hilft' Dir, etwas zu finden, was Du Dir ansehen moechtest, weil Du
es ohne Kenntnis der konkreten Umstaende fuer "per se problematisch"
haelst, naemlich eine C-Zuweisung die so funktioniert, wie C-Zuweisungen
funktionieren, und vor die noch niemand ein (mehr Typ hier) genagelt hat,
was dort nach Deiner Ansicht immer stehen sollte.

Siehe auch "politische Ansicht". Deine Ansichten darueber, wie C
eigentlich haette definiert sein sollen helfen mir allerdings gar nicht.
Оlе Ѕtrеісhеr
2018-05-30 19:40:18 UTC
Permalink
Post by Rainer Weikusat
[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Оlе Ѕtrеісhеr
#define FOOBAR
#include "voodoo.h"
#include "foo.h"
#include "bar.h"
#ifndef BARFOO_T
#include "foobar.h"
#endif
void kunkle(int a) {
voobar = a;
}
int lenku(void) {
return voobar;
}
[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Das Beispiel ist nicht ausgedacht, sondern entstammt im Wesentlichen dem
Quellcode von IRAF (genaugenommen dem "ecl" Paket darin).
https://github.com/iraf/iraf-v216/blob/master/pkg/ecl/main.c#L310
Die referenzierte Zeile ist
currentask->t_topcs = topcs;
Inwiefern das obigem aehneln soll, verstehe ich nicht.
Der Unterschied ist lediglich, dass die Zielvariable Teil einer Struktur
ist. Welchen Typ sie hat, ist aus dem Code hier nicht unmittelbar
ersichtlich. Du wirst mir zubilligen, dass ich das Beispiel auf das
Wesentliche verkürze; und dass t_topcs Teil einer Struktur ist, ist für
das Problem unwesentlich.
Dass ich daraus einen Getter und einen Setter gemacht habe, geschah nur,
um das Problem prägnanter zu machen.
War das jetzt verständlich genug?
Es soll ihm also nicht aehneln.
Mein Beispiel ähnelt seinem Vorbild strukturell: Zuweisung ohne
explizite Angabe der Typumwandlung, Definition der Datentypen in
Includefiles.

Kannst Du wirklich nicht soweit abstrahieren?
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Frage: Gehen bei dieser Zuweisung signifikante bits verloren?
Um diese Frage beantworten zu koennen, muesste man den nicht angegebenen
Typ der Variablen kennen. Ferner muesste eine Datenflussanalyse ergeben,
das reale Werte von a tatsaechlich mehr Bits haben, als in voobar zur
Verfuegung stehen und es muesste auch noch wenigstens eine Codestelle
geben, deren Verhalten fehlerhaft ist, weil die entsprechenden Bits
unter den Tisch fielen.
Eine "Zieltyp kuerzer als Quelltyp!"-Warnung hilft hier direkt nichts.
Doch. Sie hilft nämlich zu erkennen, dass es hier ein Problem geben
könnte und man sich die Stelle genauer ansehen müsste.
Sie 'hilft' Dir, etwas zu finden, was Du Dir ansehen moechtest, weil Du
es ohne Kenntnis der konkreten Umstaende fuer "per se problematisch"
haelst, naemlich eine C-Zuweisung die so funktioniert, wie C-Zuweisungen
funktionieren, und vor die noch niemand ein (mehr Typ hier) genagelt hat,
was dort nach Deiner Ansicht immer stehen sollte.
Wo habe ich geschrieben, dass das "per se problematisch" ist? Es ist ein
nach meinen Erfahrungen nicht untypischer Fehler, dass sich ein Autor
bei einer Zuweisung unklar über die Datentypen ist und dabei Bits oder
Vorzeichen verlorengehen. Darum sind entsprechende Stellen jene, die ich
mir in einem >>100-kZeilen-Projekt vorrangig anschaue. Ein Compiler, der
mir die passenden Stellen nennt, ist dabei sehr hilfreich.

Und letzteres nennt man "Warnung". Eine Warnung zeigt keine "per se
problematischen" Stellen, sondern "potentiell problematische" Stellen
an. Ob sie problematisch sind, zeigt eine darauffolgende Analyse.
Post by Rainer Weikusat
Siehe auch "politische Ansicht". Deine Ansichten darueber, wie C
eigentlich haette definiert sein sollen helfen mir allerdings gar nicht.
Häh? Wo habe ich geschrieben, "wie C eigentlich haette definiert sein
sollen"???

Ich habe über den Sinn einer Compilerwarnung geschrieben. Eine
Compilerwarnung zeigt nicht, "wie C eigentlich haette definiert sein
sollen", sondern weist auf potentiell problematischen Code hin. Und
speziell *diese* Warnung hat mir auch schon geholfen, fehlerhaften Code
zu finden, also ist sie sinnvoll. Wenn sie für dich nicht sinnvoll ist,
schalte sie einfach ab. Aber was Du da mit "per se" hineininterpretieren
möchtest, erschließt sich mir nicht.

Ole
Stefan Reuther
2018-05-29 17:41:45 UTC
Permalink
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt
Ein Grund könnte aus der Auswertung typischer Bugs folgen: Wenn ein
Fehler regelmäßig wieder gemacht wird, ist es ein guter Grund, eine
Warnung einzubauen.
Man kann aber keine "typischen Bugs" auswerten. Man kann Statistiken
ueber Fehler in irgendwelchen Code-Mengen anlegen. Damit bekommt man
historische Information darueber, was die Autoren dieses Codes zum
fraglichen Zeitpunkt wie haeufig falsch gemacht haben. Weiteren
Aussagewert hat das keinen.
Heerscharen von Mathematikern beschäftigen sich damit, wie man aus der
Vergangenheit aus die Zukunft extrapolieren kann, welche
Rahmenbedingungen da gelten und welche Sicherheit die Vorhersagen haben.
Dass die Entwicklerschar, die den gleichen Fehler schon 50 Mal gemacht
hat, den auch in Bälde ein 51. Mal macht, ist durchaus wahrscheinlicher,
als dass ausgerechnet jetzt die große Erleuchtung einsetzt und der
Fehler nie wieder auftreten wird.

Dass allerdings ausgerechnet Typumwandlungen die Hitliste anführen
würden, bezweifle ich. Und das sag ich als einer, der Statistiken über
Warnungen und dazugehörige Bugs führt.

Einen Cluster gibt es allerdings in der Tat: Code aus prä-intptr_t-
Zeiten hat auf 64-bit-Systemen gerne mal Probleme, wenn er Zeiger in
Zahlen und andersherum wandelt. Gut, dass es da Warnungen gibt, um auf
Problemstellen hinzuweisen.


Stefan
Rainer Weikusat
2018-05-30 14:12:42 UTC
Permalink
Post by Stefan Reuther
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Halten wir mal fest, dass ich fuer eine bestimmte Ansicht argumentiert
habe (naemlich dass es keine Warnungen fuer Zuweisungen, die irrelevante
Teile eines laengeren Integers unter den Tisch fallen lassen,
argumentiert habe - es gibt keinen Grund zu der Annahme, dass solche
"inherent wahrscheinlicher falsch" sein sollten, als jede andere
Operation, die die Sprache bereitstellt
Ein Grund könnte aus der Auswertung typischer Bugs folgen: Wenn ein
Fehler regelmäßig wieder gemacht wird, ist es ein guter Grund, eine
Warnung einzubauen.
Man kann aber keine "typischen Bugs" auswerten. Man kann Statistiken
ueber Fehler in irgendwelchen Code-Mengen anlegen. Damit bekommt man
historische Information darueber, was die Autoren dieses Codes zum
fraglichen Zeitpunkt wie haeufig falsch gemacht haben. Weiteren
Aussagewert hat das keinen.
Heerscharen von Mathematikern beschäftigen sich damit, wie man aus der
Vergangenheit aus die Zukunft extrapolieren kann,
Heerscharen von Mathematikern pflegten das bis ca 2008 auch fuer
Boerseninvestitionen zu tun. Weil sich recht demonstrativ herausgestellt
hat, dass das nicht funktioniert, gibt es mittlerweile (wenigstens in
England) vorgeschriebene Warnhinweise a la "The value of an investment
can go up and down and past performance is not a reliable indicator for
future events" ueber die ich mich bei jedem Lesen aufs neue freue.
Hans-Peter Diettrich
2018-05-30 21:00:53 UTC
Permalink
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Erweitern geht auch hier immer, nur
beim Verkürzen sollte mindestens eine Warnung "significant bits lost"
o.ä. vom Compiler kommen.
Das sehe ich nicht so.
Ich schon, denn das könnte ein Hinweis auf einen potentiellen Fehler
sein. Der Programmierer kann ja, wenn er die Situation erfolgreich
geprüft hat, immer noch casten und damit die Warnung an dieser Stelle
eliminieren.
Auf der Basis derselben Logik koennte man auch eine "Subtraction
operator detected, sure you didn't mean multiplication?" ausgeben
lassen: Alles, was im Code steht, ist potentiell falsch.
Es ist potentiell falsch, wenn eine Operation den Wertebereich der
vorgegebenen Typen überschreitet. Das kann der Compiler definitiv
feststellen. Ob irgendwo X oder U stehen sollte, das kann der Compiler
nicht feststellen.

DoDi
Rainer Weikusat
2018-05-30 21:20:45 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Rainer Weikusat
Post by Claus Reibenstein
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Erweitern geht auch hier immer, nur
beim Verkürzen sollte mindestens eine Warnung "significant bits lost"
o.ä. vom Compiler kommen.
Das sehe ich nicht so.
Ich schon, denn das könnte ein Hinweis auf einen potentiellen Fehler
sein. Der Programmierer kann ja, wenn er die Situation erfolgreich
geprüft hat, immer noch casten und damit die Warnung an dieser Stelle
eliminieren.
Auf der Basis derselben Logik koennte man auch eine "Subtraction
operator detected, sure you didn't mean multiplication?" ausgeben
lassen: Alles, was im Code steht, ist potentiell falsch.
Es ist potentiell falsch, wenn eine Operation den Wertebereich der
vorgegebenen Typen überschreitet.
Wenn sie das nicht tut, ist sie genauso "potentiell falsch". ZB habe ich
gerade einen Fehler verbessert wo in folgendem Code:

---------
static size_t process_valid_msgs(unsigned char *d, size_t d_len, int *send_ka_reply)
{
unsigned char *e;
size_t rc, remain;
unsigned type, len;

e = d + d_len;
*send_ka_reply = 0;
while ((remain = e - d) >= MIN_VALID) {
rc = validate_header(d, remain);
if (rc == -1) return rc;
---------

anstelle der "wertebereichskomischen" (aber richtigen) -1 eine
wertebereichskonforme 1 stand. Die Zuweisung, die von ptrdiff_t nach
size_t konvertiert, ist uebrigens auch richtig.
Helmut Schellong
2018-05-31 09:47:30 UTC
Permalink
Post by Rainer Weikusat
ZB habe ich
Einen Fehler verbessert, so daß er nun ein besserer Fehler ist?
--
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-05-31 09:53:19 UTC
Permalink
On 05/30/2018 23:20, Rainer Weikusat wrote:
[...]
Post by Rainer Weikusat
rc = validate_header(d, remain);
if (rc == -1) return rc;
anstelle der "wertebereichskomischen" (aber richtigen) -1 eine
wertebereichskonforme 1 stand. Die Zuweisung, die von ptrdiff_t nach
size_t konvertiert, ist uebrigens auch richtig.
Da gebe ich zu bedenken, daß -1 nur bei Zweierkomplement
1111111111111111...111₂ ist.
--
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-05-31 12:03:08 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Rainer Weikusat
rc = validate_header(d, remain);
if (rc == -1) return rc;
anstelle der "wertebereichskomischen" (aber richtigen) -1 eine
wertebereichskonforme 1 stand. Die Zuweisung, die von ptrdiff_t nach
size_t konvertiert, ist uebrigens auch richtig.
Da gebe ich zu bedenken, daß -1 nur bei Zweierkomplement
1111111111111111...111₂ ist.
Das Konvertierungsergebnis ist davon unabhängig.
Rainer Weikusat
2018-05-31 12:13:43 UTC
Permalink
Post by Helmut Schellong
[...]
Post by Rainer Weikusat
rc = validate_header(d, remain);
if (rc == -1) return rc;
anstelle der "wertebereichskomischen" (aber richtigen) -1 eine
wertebereichskonforme 1 stand. Die Zuweisung, die von ptrdiff_t nach
size_t konvertiert, ist uebrigens auch richtig.
Da gebe ich zu bedenken, daß -1 nur bei Zweierkomplement
1111111111111111...111₂ ist.
Das ist an dieser Stelle uninteressant, weil die Konvertierungsregeln
fuer vorzeichenlose Typen dieses Ergebnis vorschreiben ("repeatedly add or
subtract one more than the maximum value which can be represented until
the result is in the range of the type").

Dh -1 ist eine 'Universalrepraesentation' fuer "maximaler Wert eines
beliebigen, vorzeichenlosen Typs".
Helmut Schellong
2018-05-31 16:23:41 UTC
Permalink
[...]
Post by Rainer Weikusat
Post by Helmut Schellong
Da gebe ich zu bedenken, daß -1 nur bei Zweierkomplement
1111111111111111...111₂ ist.
Das ist an dieser Stelle uninteressant, weil die Konvertierungsregeln
fuer vorzeichenlose Typen dieses Ergebnis vorschreiben ("repeatedly add or
subtract one more than the maximum value which can be represented until
the result is in the range of the type").
Dh -1 ist eine 'Universalrepraesentation' fuer "maximaler Wert eines
beliebigen, vorzeichenlosen Typs".
Stimmt, ich war geblendet von der häufigen Verwendung
von -1 des Compilers in Assembler.
Aber Assembler ist nun mal nicht C.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Hans-Peter Diettrich
2018-05-30 21:01:00 UTC
Permalink
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Typ-Erweiterung erfolgt bei der Evaluierung eines Ausdrucks bei
Bedarf, und immer in Richtung des größeren Datentyps.
c = x;
ist ein Ausdruck. Insofern c in x Zahlen sind, wird der Wert von x in
den Typ von C konvertiert.
Das gilt nur für die Zuweisung, und das ist keine Evaluierung.
Post by Rainer Weikusat
x + x
ist auch ein Ausdruck. Auch hier wird automatisch konvertiert, falls
notwendig.
Was sollte da konvertiert werden, wo steht das?

DoDi
Thomas Koenig
2018-05-31 12:01:51 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Typ-Erweiterung erfolgt bei der Evaluierung eines Ausdrucks bei
Bedarf, und immer in Richtung des größeren Datentyps.
c = x;
ist ein Ausdruck. Insofern c in x Zahlen sind, wird der Wert von x in
den Typ von C konvertiert.
Das gilt nur für die Zuweisung, und das ist keine Evaluierung.
Was ist mit dem Ausdruck

1 + 1.0

?
Hans-Peter Diettrich
2018-06-01 15:48:34 UTC
Permalink
Post by Thomas Koenig
Was ist mit dem Ausdruck
1 + 1.0
Was soll damit sein? Da das Ergebnis nicht weiter benutzt wird, muß hier
garnichts berechnet werden.

Ansonsten ist der Typ des Ergebnisses der von 1.0, vermutlich also float.

DoDi
Juergen Ilse
2018-06-01 16:50:00 UTC
Permalink
Hallo,
Post by Hans-Peter Diettrich
Post by Thomas Koenig
Was ist mit dem Ausdruck
1 + 1.0
Was soll damit sein? Da das Ergebnis nicht weiter benutzt wird, muß hier
garnichts berechnet werden.
Ansonsten ist der Typ des Ergebnisses der von 1.0, vermutlich also float.
Nein, double.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Helmut Schellong
2018-06-02 09:37:59 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Thomas Koenig
Was ist mit dem Ausdruck
1 + 1.0
Was soll damit sein? Da das Ergebnis nicht weiter benutzt wird, muß hier
garnichts berechnet werden.
Ein Ausdruck ist keine mit einem Semikolon abgeschlossene Anweisung.
--
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-05-31 14:31:38 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Rainer Weikusat
Post by Hans-Peter Diettrich
Typ-Erweiterung erfolgt bei der Evaluierung eines Ausdrucks bei
Bedarf, und immer in Richtung des größeren Datentyps.
c = x;
ist ein Ausdruck. Insofern c in x Zahlen sind, wird der Wert von x in
den Typ von C konvertiert.
Das gilt nur für die Zuweisung, und das ist keine Evaluierung.
Aber ganz sicher doch: = ist in C ein Operator, c = x somit ein
Ausdruck, der ausgewertet wird.
Post by Hans-Peter Diettrich
Post by Rainer Weikusat
x + x
ist auch ein Ausdruck. Auch hier wird automatisch konvertiert, falls
notwendig.
Was sollte da konvertiert werden, wo steht das?
Fchreibsehler. Das sollte

c + x

werden.

6.3.1.8, "Usual arithmetic conversions".
Helmut Schellong
2018-04-25 10:00:47 UTC
Permalink
[...]
Ich ergänze noch spielerisch:

a[i]
*(a+i)
(a+i)[0]
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Loading...