Discussion:
Protoize/Unprotoize
(zu alt für eine Antwort)
Оlе Ѕtrеісhеr
2017-08-31 12:06:09 UTC
Permalink
Raw Message
Hallo,

aus meinen Kindergartentagen erinnere ich mich an ein Tool(paar)
"protoize" (und "unprotoize"), welches K&R C in C mit Prototypen
umwandelt.

Nun habe ich seit einiger Zeit ein größeres Programmpaket in der Mache,
das (nicht konsequent) in K&R C geschrieben ist und hinreichend
buggy. Prototypen könnten da womöglich den einen oder anderen Bug
finden.

...nur das Tool ist jetzt weg? Debian (die ja sonst alles haben ;-) )
hat nirgendwo mehr ein Binary "protoize". Die allwissende Müllhalde
findet zwar manpages, aber keinen Source code. Es war wohl mal Teil von
gcc-3.3. Und vorher war es selbständig; es gibt ein Announcement von
1990, dass die Version 1.38 verfügbar sei.

Weiß jemand da Genaueres? Wo ist es abgeblieben und warum ist es
verschwunden?

Schöne Grüße

Ole
Rainer Weikusat
2017-08-31 14:03:50 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
aus meinen Kindergartentagen erinnere ich mich an ein Tool(paar)
"protoize" (und "unprotoize"), welches K&R C in C mit Prototypen
umwandelt.
[...]
Post by Оlе Ѕtrеісhеr
...nur das Tool ist jetzt weg? Debian (die ja sonst alles haben ;-) )
hat nirgendwo mehr ein Binary "protoize".
[***@doppelsaurus]/tmp#sudo apt-cache search protoize
protoize - Create/remove ANSI prototypes from C code

Das ist von einem Debian 7. Liess sich auch via apt-get installieren.
Оlе Ѕtrеісhеr
2017-08-31 14:16:07 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
aus meinen Kindergartentagen erinnere ich mich an ein Tool(paar)
"protoize" (und "unprotoize"), welches K&R C in C mit Prototypen
umwandelt.
[...]
Post by Оlе Ѕtrеісhеr
...nur das Tool ist jetzt weg? Debian (die ja sonst alles haben ;-) )
hat nirgendwo mehr ein Binary "protoize".
protoize - Create/remove ANSI prototypes from C code
Das ist von einem Debian 7. Liess sich auch via apt-get installieren.
Klar, Debian 7 hatte es noch. Das war 2013, heute "oldoldstable"; das
Paket wurde aus den gcc-Sourcen gebaut. Aber dann ist es verschwunden.

Wheezy lässt sich auch nicht mehr ohne weiteres in einem Buster-Chroot
betreiben, sodass Archäologie langsam mühsam wird.

Schöne Grüße

Ole
Bastian Blank
2017-08-31 14:21:48 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Klar, Debian 7 hatte es noch. Das war 2013, heute "oldoldstable"; das
Paket wurde aus den gcc-Sourcen gebaut. Aber dann ist es verschwunden.
Und im Changelog findet man auch den Grund:

| * Stop building the protoize package, removed from the GCC 4.5 sources.

Bastian
Оlе Ѕtrеісhеr
2017-08-31 14:31:11 UTC
Permalink
Raw Message
Post by Bastian Blank
Post by Оlе Ѕtrеісhеr
Klar, Debian 7 hatte es noch. Das war 2013, heute "oldoldstable"; das
Paket wurde aus den gcc-Sourcen gebaut. Aber dann ist es verschwunden.
| * Stop building the protoize package, removed from the GCC 4.5 sources.
Das ist mir auch klar. Aber warum ist es aus gcc verschwunden? Und wo
sind die ursprünglichen Quellen hin?

Bin ich der einzige, der manchmal in den Sünden unserer Urväter wühlt
und versucht, da noch was sinnvolles herauszuholen?

Schöne Grüße

Ole
Rainer Weikusat
2017-08-31 15:03:49 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
aus meinen Kindergartentagen erinnere ich mich an ein Tool(paar)
"protoize" (und "unprotoize"), welches K&R C in C mit Prototypen
umwandelt.
[...]
Post by Оlе Ѕtrеісhеr
...nur das Tool ist jetzt weg? Debian (die ja sonst alles haben ;-) )
hat nirgendwo mehr ein Binary "protoize".
protoize - Create/remove ANSI prototypes from C code
Das ist von einem Debian 7. Liess sich auch via apt-get installieren.
Klar, Debian 7 hatte es noch. Das war 2013, heute "oldoldstable"; das
Paket wurde aus den gcc-Sourcen gebaut. Aber dann ist es verschwunden.
Wheezy lässt sich auch nicht mehr ohne weiteres in einem Buster-Chroot
betreiben, sodass Archäologie langsam mühsam wird.
Ehh ... das ist ein Binary, welches man hic et nunc von einem
Debian-server herunterladen kann. Die Behauptung es waere 'verschwunden'
ist somit mal definitiv falsch. Das Program braucht nichts ausser der
C-library, sollte also problemfrei auf neueren System benutzbar sein[*],
und wenn sonst nichts hilft, sollte man den Quellcode von ebendemselben
Debian-Server bekommen koennen (und vermutlich von allen moeglichen
anderen Orten).

[*] Inwiefern diese irgendwannmal vorhandende Binaerkompatibiliaet
mittlerweile vom systemd-Projekt als "auslaendisches Teufelszeug"
abgeschafft wurde oder vielleicht gar das Programm selber aus dem
Rechner gesprungen kommt, um den heidnischen Suender an Ort und
Stelle zu verbrennen etc ist mir ebenso unbekannt wie gleichgueltig.
Оlе Ѕtrеісhеr
2017-08-31 15:25:38 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
protoize - Create/remove ANSI prototypes from C code
Das ist von einem Debian 7. Liess sich auch via apt-get installieren.
Klar, Debian 7 hatte es noch. Das war 2013, heute "oldoldstable"; das
Paket wurde aus den gcc-Sourcen gebaut. Aber dann ist es verschwunden.
Wheezy lässt sich auch nicht mehr ohne weiteres in einem Buster-Chroot
betreiben, sodass Archäologie langsam mühsam wird.
[umsortiert]
Post by Rainer Weikusat
Ehh ... das ist ein Binary, welches man hic et nunc von einem
Debian-server herunterladen kann. [...] Das Program braucht nichts ausser der
C-library, sollte also problemfrei auf neueren System benutzbar sein[*],
https://packages.debian.org/wheezy/protoize

dep: gcc-4.4 (>= 4.4.7-2)

Klar kann ich mir auch den ganzen gcc-4.4 dazu reinziehen...
Post by Rainer Weikusat
Die Behauptung es waere 'verschwunden' ist somit mal definitiv falsch.
Es ist verschwunden aus modernen Distributionen. Etwas, das mit "oldold"
anfängt, ist definitiv nicht mehr modern; zumindest nach meiner
Definition.

Und die Quellen sind verschwunden; zumindest die des unabhängigen Tools.
Post by Rainer Weikusat
und wenn sonst nichts hilft, sollte man den Quellcode von ebendemselben
Debian-Server bekommen koennen (und vermutlich von allen moeglichen
anderen Orten).
Klar. In den gcc-Quellen, und zusammen mit diesen. Die Abhängigkeit von
gcc-4.4 steht da sicher nicht ohne Grund drin.

Schöne Grüße

Ole
Rainer Weikusat
2017-08-31 15:44:46 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
protoize - Create/remove ANSI prototypes from C code
Das ist von einem Debian 7. Liess sich auch via apt-get installieren.
Klar, Debian 7 hatte es noch. Das war 2013, heute "oldoldstable"; das
Paket wurde aus den gcc-Sourcen gebaut. Aber dann ist es verschwunden.
Wheezy lässt sich auch nicht mehr ohne weiteres in einem Buster-Chroot
betreiben, sodass Archäologie langsam mühsam wird.
[umsortiert]
Post by Rainer Weikusat
Ehh ... das ist ein Binary, welches man hic et nunc von einem
Debian-server herunterladen kann. [...] Das Program braucht nichts ausser der
C-library, sollte also problemfrei auf neueren System benutzbar sein[*],
https://packages.debian.org/wheezy/protoize
dep: gcc-4.4 (>= 4.4.7-2)
Klar kann ich mir auch den ganzen gcc-4.4 dazu reinziehen...
Du koenntest auch mal darueber nachdenken, das Problem, dass Du zu haben
glaubst, zu loesen, wie es Dir vorgeschlagen wurde, anstatt Dich
darueber zu beschweren, dass die vorgeschlagene Prozedur aber die
falsche Farbe hat (!!).

Das .deb file kann man sich herunterladen und mit ar
ausinandernehmen. Man bekommt dann ein protoize binary. Das kann man auf
ein Zielsystem kopieren, auf dem der angeblich benoetigte Compiler
garantiert nicht vorhanden ist und - siehe da -
#include <stdio.h>

hello(n)
char *n;
{
printf("Hello, %s\n", n);
}

main()
{
hello("Rabbit");
return 0;
}
[***@duesterwald]/tmp $./protoize a.c
protoize: compiling 'a.c'
protoize: warning: missing SYSCALLS file '/usr/lib/gcc/x86_64-linux-gnu/4.4.7/SYSCALLS.c.X'
protoize: converting file 'a.c'
a.c: 3: warning: 'hello' excluded by preprocessing
protoize: function definition not converted
a.c: 9: warning: 'main' excluded by preprocessing
protoize: function definition not converted
protoize: warning: file 'a.c' already saved in 'a.c.save'
[***@duesterwald]/tmp $cat a.c
#include <stdio.h>

hello(char *n)
{
printf("Hello, %s\n", n);
}

main(void)
{
hello("Rabbit");
return 0;
}

... es funktioniert.

Fuer ein reales Problem wird das vielleicht nicht ganz so einfach, aber
loesbar sollte es trotzdem sein. Nur tun muss mans ...
Оlе Ѕtrеісhеr
2017-08-31 15:58:54 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
protoize - Create/remove ANSI prototypes from C code
Das ist von einem Debian 7. Liess sich auch via apt-get installieren.
Klar, Debian 7 hatte es noch. Das war 2013, heute "oldoldstable"; das
Paket wurde aus den gcc-Sourcen gebaut. Aber dann ist es verschwunden.
Wheezy lässt sich auch nicht mehr ohne weiteres in einem Buster-Chroot
betreiben, sodass Archäologie langsam mühsam wird.
[umsortiert]
Post by Rainer Weikusat
Ehh ... das ist ein Binary, welches man hic et nunc von einem
Debian-server herunterladen kann. [...] Das Program braucht nichts ausser der
C-library, sollte also problemfrei auf neueren System benutzbar sein[*],
https://packages.debian.org/wheezy/protoize
dep: gcc-4.4 (>= 4.4.7-2)
Klar kann ich mir auch den ganzen gcc-4.4 dazu reinziehen...
Du koenntest auch mal darueber nachdenken, das Problem, dass Du zu haben
glaubst, zu loesen, wie es Dir vorgeschlagen wurde, anstatt Dich
darueber zu beschweren, dass die vorgeschlagene Prozedur aber die
falsche Farbe hat (!!).
Ich habe letztlich sogar noch ein funktionierendes Stretch gefunden,
welches ein chroot in ein Wheezy erlaubt.

Das ändert aber nichts an meiner Verwunderung über das Verschwinden;
sowohl in gcc als auch als separates Paket: das Announcement findet
sich, das Paket selber nicht mehr. Verwunderung deshalb, weil es ja
immer noch K&R-Code gibt, der sich vielleicht zu erhalten lohnt.

Wenn Du diese Verwunderung als Beschwerde auffasst, dann solltest Du
Deine Detektoren mal kalibrieren.

Schöne Grüße

Ole
Stefan Reuther
2017-09-01 07:52:51 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Das ändert aber nichts an meiner Verwunderung über das Verschwinden;
sowohl in gcc als auch als separates Paket: das Announcement findet
sich, das Paket selber nicht mehr. Verwunderung deshalb, weil es ja
immer noch K&R-Code gibt, der sich vielleicht zu erhalten lohnt.
Als ich das letzte Mal vor dieser Aufgabe stand (das ist allerdings auch
schon ein Weilchen her) hab ich das händisch gemacht und dabei den
Funktionsparametern gleich noch 'const'-Attribute spendiert, die
protoize nie gefunden hätte.

Ansonsten führen wie immer mehrere Wege zum Ziel. "Das Binary aus dem
alten .deb extrahieren" ist einer. Selber bauen ein anderer, ich meine,
das Tool hat keine sonderlich großen Abhängigkeiten (hier wäre z.B.
protoize.c von gcc 4.4.7:
https://github.com/gcc-mirror/gcc/blob/ed635cb211f42b70efa52f4b25aa91c29ee29c71/gcc/protoize.c).

Kurzes Rumgeklicke im Netz findet noch http://cproto.sourceforge.net/
und
https://github.com/inverse-inc/openchange/blob/master/script/mkproto.pl,
die behaupten, ähnliches zu tun.


Stefan
Оlе Ѕtrеісhеr
2017-09-01 08:25:52 UTC
Permalink
Raw Message
Post by Stefan Reuther
Post by Оlе Ѕtrеісhеr
Das ändert aber nichts an meiner Verwunderung über das Verschwinden;
sowohl in gcc als auch als separates Paket: das Announcement findet
sich, das Paket selber nicht mehr. Verwunderung deshalb, weil es ja
immer noch K&R-Code gibt, der sich vielleicht zu erhalten lohnt.
Als ich das letzte Mal vor dieser Aufgabe stand (das ist allerdings auch
schon ein Weilchen her) hab ich das händisch gemacht
War auch mein erster Gedanke. Aber bei knapp 100.000 Zeilen brutto macht
das keinen Spaß.
Post by Stefan Reuther
und dabei den Funktionsparametern gleich noch 'const'-Attribute
spendiert, die protoize nie gefunden hätte.
Na, die kann ich dann auch notfalls manuell einfügen. Früher war nab da
ja deutlich lässiger, sodass es im Grunde nur libc-Definitionen betrifft
(und die sollten eh durch entsprechende #includes kommen).
Post by Stefan Reuther
Ansonsten führen wie immer mehrere Wege zum Ziel.
Ist schon klar; mein Weg ist halt ein (s)chroot. Das will ich letztlich
sowieso haben, fürs Debugging.
Post by Stefan Reuther
https://github.com/gcc-mirror/gcc/blob/ed635cb211f42b70efa52f4b25aa91c29ee29c71/gcc/protoize.c).
Mich wundert halt nur, dass ein früher nicht unwichtiges Tool so in
Vergessenheit geraten ist. Klar wird es seltener eingesetzt (irgendwann
ist einfach aller Code konvertiert), da aber z.B. gcc noch K&R C
akzeptiert, schwirrt da sicher noch einiges unentdeckt herum.
Post by Stefan Reuther
Kurzes Rumgeklicke im Netz findet noch http://cproto.sourceforge.net/
Ah, das scheint einen Versuch wert. Brauche ich offenbar nicht mal mehr
kompilieren :-)

Schöne Grüße

Ole
Florian Weimer
2017-09-02 07:56:37 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Mich wundert halt nur, dass ein früher nicht unwichtiges Tool so in
Vergessenheit geraten ist. Klar wird es seltener eingesetzt (irgendwann
ist einfach aller Code konvertiert), da aber z.B. gcc noch K&R C
akzeptiert, schwirrt da sicher noch einiges unentdeckt herum.
Seit GCC 3.0 (Juni 2001) wurde es von GCC nur intern verwendet, um die
System-Header-Dateien zu modernisieren, und nicht mehr zusammen mit
dem Compiler installiert. In GCC 4.5 gab es dann schließlich keine
unterstützten Systeme mehr, die das benötigten. Die Entfernung wurde
zusammen mit GCC 4.4 angeköndigt (April 2009).

Soweit ich weiß, hat sich niemand beschwert, so daß die GCC-Entwickler
davon ausgingen, daß es keine Nutzer mehr gab.
Rainer Weikusat
2017-09-01 15:52:40 UTC
Permalink
Raw Message
[protoize]
Post by Stefan Reuther
Ansonsten führen wie immer mehrere Wege zum Ziel. "Das Binary aus dem
alten .deb extrahieren" ist einer. Selber bauen ein anderer, ich meine,
das Tool hat keine sonderlich großen Abhängigkeiten
Es braucht einen gcc-kompatiblen (wahrscheinlich)
C-compiler. 'Normalerweise' (dh im Upstream-Quellcode) wuerde es
versuchen, diesen als 'gcc' aufzurufen. Allerdings scheint das
Debian-binary, das ich aufgetrieben hatte, stattdessen mit "gcc-4.4"
uebersetzt worden zu sein.
Juergen Ilse
2017-09-04 02:21:03 UTC
Permalink
Raw Message
Hallo,
Post by Оlе Ѕtrеісhеr
Das ändert aber nichts an meiner Verwunderung über das Verschwinden;
sowohl in gcc als auch als separates Paket: das Announcement findet
sich, das Paket selber nicht mehr. Verwunderung deshalb, weil es ja
immer noch K&R-Code gibt, der sich vielleicht zu erhalten lohnt.
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist und sich
vermutlich unter den gcc Entwicklern niemand mehr gefunden hat, der das
weiter pflegen wollte, war es eigentlich nur konsequent, das Tool in
aktuellen GCC Versionen nicht mehr mitzuschleppen ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Оlе Ѕtrеісhеr
2017-09-04 06:45:39 UTC
Permalink
Raw Message
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist [...]
Wenn dem so *wäre*, warum wird dann Support für K&R C immer noch in den
gängigen Compilern mitgeschleppt? Das muss schließlich auch jemand betreuen.

Ein entsprechender Rauswurf würde auch meine Position gegenüber den
Orginalautoren stärken, die da mit "warum denn? hat doch all die Jahre
irgendwie funktioniert. Und die Fehler, die Du mit Prototypen gefunden
hast, sind ja nett; aber die können wir auch beseitigen, ohne Prototypen
einzuführen."

Der Grad des Altersstarrsinns ist da wahrscheinlich je nach Branche
verschieden. Oder Entwickler werden in dem Bereich, in dem Du arbeitest,
nicht alt :-)

SCNR

Ole
Rainer Weikusat
2017-09-04 12:40:04 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist [...]
Wenn dem so *wäre*, warum wird dann Support für K&R C immer noch in den
gängigen Compilern mitgeschleppt? Das muss schließlich auch jemand betreuen.
Weil die C-Norm das fordert.

Es ist auch nicht wirklich sinnvoll, existierenden Code bloss
deswegen zu aendern, weil neuere Sprachfeatures fuer neugeschriebenen
Code irgendetwas einfacher machen (wenigstens hoffentlich).

Es gibt uebrigens auch in neuem Code Situation, wo man (dh in diesem
Fall ich) auf etwas wie

int (*function)(); /* Es reicht! */

zurueckgreift, weil der Aufwand, noch mal drei Tage damit zuzubringen,
alle moeglichen kosmetischen Aenderungen an existierendem Code zu machen
nur damit die Typ-Ueberpruefung gluecklich ist, nicht zu rechtfertigen
ist.

Dh die Idee, dass die richtigen Argumente diejenigen sind, die der
Aufrufer uebergibt, ist durchaus immer noch nuetzlich (wenigstens in
C).
Post by Оlе Ѕtrеісhеr
Ein entsprechender Rauswurf würde auch meine Position gegenüber den
Orginalautoren stärken, die da mit "warum denn? hat doch all die Jahre
irgendwie funktioniert. Und die Fehler, die Du mit Prototypen gefunden
hast, sind ja nett; aber die können wir auch beseitigen, ohne Prototypen
einzuführen."
Und was ist das Problem damit?

Anstatt grossflaechig den Text zu aendern (und somit potentiell alle
moeglichen neuen Fehler einzufuehren), waere es meiner Ansicht nach
sinnvoller, K&R-Funktionskopfzeilen optional als Prototypen behandeln zu
koennen. Dh es sollte moeglich sein, aus einer .c-Datei eine
Interfacedefinition zu generieren, die fuer Aufruf-Typueberpruefung
benutzt werden kann.

Soetwas sollte im Rahmen einer zusaetzlichen, statischen Analyse
stattfinden, dh in Form von etwas, das man sich nur ansieht, wenn man
das moechte.
Peter J. Holzer
2017-09-04 20:24:30 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist [...]
Wenn dem so *wäre*, warum wird dann Support für K&R C immer noch in den
gängigen Compilern mitgeschleppt? Das muss schließlich auch jemand betreuen.
Weil die C-Norm das fordert.
Es ist auch nicht wirklich sinnvoll, existierenden Code bloss
deswegen zu aendern, weil neuere Sprachfeatures fuer neugeschriebenen
Code irgendetwas einfacher machen (wenigstens hoffentlich).
Meiner Meinung nach ist "irgendetwas einfacher machen" ein sehr guter
Grund dafür, existierenden Code zu ändern.
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Ein entsprechender Rauswurf würde auch meine Position gegenüber den
Orginalautoren stärken, die da mit "warum denn? hat doch all die Jahre
irgendwie funktioniert. Und die Fehler, die Du mit Prototypen gefunden
hast, sind ja nett; aber die können wir auch beseitigen, ohne Prototypen
einzuführen."
Äh, es gibt allen Ernstes, C-Programmierer, die im Jahr 2017 Code ohne
Prototypen weiterpflegen?

Ich dachte, Ole hätte da irgendwelchen Code ausgegraben, den sich seit
mindestens 20 Jahren kein Mensch mehr angeschaut hat.
Post by Rainer Weikusat
Und was ist das Problem damit?
Dass man aus der Einstellung dieser Programmierer durchaus Schlüsse auf
ihre Kompetenz und die Qualität ihres Codes ziehen sollte.
Post by Rainer Weikusat
Anstatt grossflaechig den Text zu aendern (und somit potentiell alle
moeglichen neuen Fehler einzufuehren), waere es meiner Ansicht nach
sinnvoller, K&R-Funktionskopfzeilen optional als Prototypen behandeln zu
koennen. Dh es sollte moeglich sein, aus einer .c-Datei eine
Interfacedefinition zu generieren, die fuer Aufruf-Typueberpruefung
benutzt werden kann.
Es ist lange her, dass ich sowas gebraucht habe, aber meiner Erinnerung
gab es in den 90er-Jahren Tools, die genau das gemacht haben: C-Code in
K&R-Syntax geparst und daraus ein Header-File mit Deklarationen mit
Prototypen generiert. Vermutlich ... ach, was soll ich lang
herumspekulieren, ich installiere jetzt einfach cproto und lese die
Man-Page. Yup, cproto macht das per default.

h "Man-Pages machen glücklich, wenn man rechtzeitig drauf
schaut, dass mans hat, wenn mans braucht" p
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Оlе Ѕtrеісhеr
2017-09-04 21:10:18 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Äh, es gibt allen Ernstes, C-Programmierer, die im Jahr 2017 Code ohne
Prototypen weiterpflegen?
Sagen wir mal: der letzte Patch mit einem Versuch (nicht von mir),
Prototypen einzufügen stammt aus dem Jahr 2009. Vom Autor ignoriert.
Post by Peter J. Holzer
Ich dachte, Ole hätte da irgendwelchen Code ausgegraben, den sich seit
mindestens 20 Jahren kein Mensch mehr angeschaut hat.
https://github.com/iraf/iraf-v216

Der ist (teilweise) >30 Jahre alt, aber immer noch in Verwendung. Heute
Legacy (IMO aufgrund der Ignoranz der Autoren), und die Pflege kann man
nicht mehr unbedingt als "liebevoll" bezeichnen.
Post by Peter J. Holzer
Post by Rainer Weikusat
Und was ist das Problem damit?
Dass man aus der Einstellung dieser Programmierer durchaus Schlüsse auf
ihre Kompetenz und die Qualität ihres Codes ziehen sollte.
Das ist halt so ein Problem. Was bei einer Festanstellung auf Lebenszeit
dann zu einem PAL wird.

Der Code war in den 80ern State Of The Art: Lauffähig auf einer Reihe
von damaligen Workstations unter ganz verschiedenen Systemen (u.a. VMS;
POSIX war noch weit weg), mit Workarounds für die teilweise "etwas"
kreative Implementierung von C und Fortran auf den verschiedenen
Platformen. Das war damals schon recht genial.

Nur zählen heute halt andere Werte: C-Implementationen sind kaum noch
ein Thema (gcc und clang sind omnipräsent und standardkonform), die
schöne Vielfalt der Systeme lässt sich (für diese Zwecke) eindampfen auf
POSIX (mit minimalen Interpretationen); dafür hätte man aber gerne eine
Standardinstallationsprozedur (wahlweise cmake oder autoconf), Unit
tests, -Wpedantic - clean code, Versionsverwaltung etc. Da können die
alten Herrschaften nicht mehr mithalten, und man kann halt nur hoffen,
dass sie irgendwann in Rente gehen. Irgendwann wird man das gleiche halt
bei uns hoffen.
Post by Peter J. Holzer
Es ist lange her, dass ich sowas gebraucht habe, aber meiner Erinnerung
gab es in den 90er-Jahren Tools, die genau das gemacht haben: C-Code in
K&R-Syntax geparst und daraus ein Header-File mit Deklarationen mit
Prototypen generiert. Vermutlich ... ach, was soll ich lang
herumspekulieren, ich installiere jetzt einfach cproto und lese die
Man-Page. Yup, cproto macht das per default.
Sender Jerewan, zumindest in meinem Fall: bei Hin- und Her-Definitionen
(Funktionsnamen, Typen mit #define etc.) kommt das Ding gerne mal
durcheinander und verweigert die Erstellung des Prototypen. Gcc kann
sowas ähnliches auch (mittels -aux-file=), aber löst dabei gnadenlos
alle #defines auf und ist damit unbrauchbar.

Letztlich habe ich cproto genommen, dann bei gcc die entsprechenden
Optionen angeschaltet (-Wold-style-definition & Co.) und dann den Rest
per Hand umgestellt. Effektives Arbeiten ist was anderes...

Protoize aus gcc-4.? ist da übrigens auch nicht besser. Es ist schon
erstaunlich, warum so eine recht überschaubare Aufgabe nicht allgemein
fehlerfrei zu lösen ist.

Schöne Grüße

Ole
Florian Weimer
2017-09-07 11:16:12 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Ich dachte, Ole hätte da irgendwelchen Code ausgegraben, den sich seit
mindestens 20 Jahren kein Mensch mehr angeschaut hat.
https://github.com/iraf/iraf-v216
Der ist (teilweise) >30 Jahre alt, aber immer noch in Verwendung. Heute
Legacy (IMO aufgrund der Ignoranz der Autoren), und die Pflege kann man
nicht mehr unbedingt als "liebevoll" bezeichnen.
Die Frage ist halt, ob jemand sich die Mühe gemacht hat, das ganze
tatsächlich richtig umzustellen, so daß der Code auch noch auf
nicht-GNU-C89-Compilern läuft oder seltsamen ABIs wie POWER ELFv2.
Viele GNU-Projekte nutzen Prototypen mit nicht exakt passenden
Funktionsdefinitionen im alten Stil, und das ist nunmal nicht
portabel. Deswegen wird das __P-Makro verwendet, damit man die
Prototypen bei Bedarf wieder loswerden kann.

Alternativ kann man natürlich den Code auch nach C89 umschreiben.
Peter J. Holzer
2017-09-08 20:09:13 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Ich dachte, Ole hätte da irgendwelchen Code ausgegraben, den sich seit
mindestens 20 Jahren kein Mensch mehr angeschaut hat.
https://github.com/iraf/iraf-v216
Der ist (teilweise) >30 Jahre alt, aber immer noch in Verwendung. Heute
Legacy (IMO aufgrund der Ignoranz der Autoren), und die Pflege kann man
nicht mehr unbedingt als "liebevoll" bezeichnen.
Die Frage ist halt, ob jemand sich die Mühe gemacht hat, das ganze
tatsächlich richtig umzustellen, so daß der Code auch noch auf
nicht-GNU-C89-Compilern läuft oder seltsamen ABIs wie POWER ELFv2.
Viele GNU-Projekte nutzen Prototypen mit nicht exakt passenden
Funktionsdefinitionen im alten Stil, und das ist nunmal nicht
portabel. Deswegen wird das __P-Makro verwendet, damit man die
Prototypen bei Bedarf wieder loswerden kann.
Meiner Meinung nach nein: Das __P-Makro war dafür da, den Code mit einem
Compiler, der keine Prototypen versteht, kompilieren zu können. Das war
bis Mitte der 90er-Jahre durchaus ein Thema. Dass man durch das
Wegdefinieren der Prototypen auch gewisse Portabilitätsprobleme
zukleistern konnte, sehe ich eher als Nebeneffekt an.

Generell war es natürlich unmöglich, zu jeder K&R-Funktionsdefinition
einen portablen Prototypen zu erstellen. Wenn man wirklich portable
Programme schreiben wollte, musste man das berücksichtigen.
Post by Florian Weimer
Alternativ kann man natürlich den Code auch nach C89 umschreiben.
Das war über kurz oder lang die effizientere Variante.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Florian Weimer
2017-09-10 21:03:22 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Florian Weimer
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Ich dachte, Ole hätte da irgendwelchen Code ausgegraben, den sich seit
mindestens 20 Jahren kein Mensch mehr angeschaut hat.
https://github.com/iraf/iraf-v216
Der ist (teilweise) >30 Jahre alt, aber immer noch in Verwendung. Heute
Legacy (IMO aufgrund der Ignoranz der Autoren), und die Pflege kann man
nicht mehr unbedingt als "liebevoll" bezeichnen.
Die Frage ist halt, ob jemand sich die Mühe gemacht hat, das ganze
tatsächlich richtig umzustellen, so daß der Code auch noch auf
nicht-GNU-C89-Compilern läuft oder seltsamen ABIs wie POWER ELFv2.
Viele GNU-Projekte nutzen Prototypen mit nicht exakt passenden
Funktionsdefinitionen im alten Stil, und das ist nunmal nicht
portabel. Deswegen wird das __P-Makro verwendet, damit man die
Prototypen bei Bedarf wieder loswerden kann.
Meiner Meinung nach nein: Das __P-Makro war dafür da, den Code mit einem
Compiler, der keine Prototypen versteht, kompilieren zu können.
Das Problem ist, daß

| extern int tcsetpgrp (int, pid_t);
|
| int
| tcsetpgrp (fd, pgrp_id)
| int fd;
| pid_t pgrp_id;
| {
| …
| }

eine GNU-Erweiterung ist. Andere C89-Compiler quittieren das mit einem
Fehler, weil sie hier als Prototyp

extern int tcsetpgrp (long, long);

erwarten, damit die Aufrufkonvention dem Nicht-Prototyp-Fall
entspricht. (Das ist m.E. das, was auch die C-Norm fordert.) Bei GNU
CC sorgt die erste Konstruktion dafür, daß die Funktionsdefinition als

| int
| tcsetpgrp (int fd, pid_t pgrp_id)
| {
| …
| }

übersetzt wird, d.h. der Prototyp ändert auch das Verhalten der
Definition. Das ist m.E. durchaus nützlich, aber entspricht nicht dem
Verhalten anderer Compiler.
Peter J. Holzer
2017-09-11 18:50:54 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Peter J. Holzer
Post by Florian Weimer
Die Frage ist halt, ob jemand sich die Mühe gemacht hat, das ganze
tatsächlich richtig umzustellen, so daß der Code auch noch auf
nicht-GNU-C89-Compilern läuft oder seltsamen ABIs wie POWER ELFv2.
Viele GNU-Projekte nutzen Prototypen mit nicht exakt passenden
Funktionsdefinitionen im alten Stil, und das ist nunmal nicht
portabel. Deswegen wird das __P-Makro verwendet, damit man die
Prototypen bei Bedarf wieder loswerden kann.
Meiner Meinung nach nein: Das __P-Makro war dafür da, den Code mit einem
Compiler, der keine Prototypen versteht, kompilieren zu können.
Das Problem ist, daß
| extern int tcsetpgrp (int, pid_t);
|
| int
| tcsetpgrp (fd, pgrp_id)
| int fd;
| pid_t pgrp_id;
| {
| …
| }
eine GNU-Erweiterung ist. Andere C89-Compiler quittieren das mit einem
Fehler, weil sie hier als Prototyp
extern int tcsetpgrp (long, long);
erwarten, damit die Aufrufkonvention dem Nicht-Prototyp-Fall
entspricht. (Das ist m.E. das, was auch die C-Norm fordert.)
Sorry, aber das ist schlicht ein Unsinn, und ich habe bereits mindestens
zwei Mal in diesem Thread gepostet, was der C-Standard wirklich
vorsieht. Hier zum dritten Mal, diesmal mit Zitaten (aus C99, weil ich
C89 nur auf Papier habe, die Regeln sind aber die gleichen):

| If the expression that denotes the called function has a type that does
| not include a prototype, the integer promotions are performed on each
| argument, and arguments that have type float are promoted to double.
| These are called the default argument promotions.
§6.5.2.2

| The following may be used in an expression wherever an int or unsigned
| int may be used:
|
| — An object or expression with an integer type whose integer
| conversion rank is less than the rank of int and unsigned int.
| — A bit-field of type _Bool, int, signed int, or unsigned int.
|
| If an int can represent all values of the original type, the value is
| converted to an int; otherwise, it is converted to an unsigned int.
| These are called the integer promotions. All other types are unchanged
| by the integer promotions.
§6.3.1.1

int bleibt im Prototyp also auf jeden Fall int (und wird nicht zu long)
("all other types are unchanged"). Bei pid_t hängt es von der Definition
von pid_t ab. Wenn pid_t (das laut POSIX ein signed integer type sein
muss) ein short oder signed char ist, dann muss im Prototypen int
("integer type whose integer conversion rank is less than the rank of
int" und "int can represent all values of the original type") stehen.
Andernfalls ist pid_t richtig ("all other types are unchanged").
Post by Florian Weimer
Bei GNU CC sorgt die erste Konstruktion dafür, daß die
Funktionsdefinition als
| int
| tcsetpgrp (int fd, pid_t pgrp_id)
| {
| …
| }
übersetzt wird, d.h. der Prototyp ändert auch das Verhalten der
Definition.
Oh, das ist mir neu. War früher (vor ca. 1995) meiner Erinnerung nach
nicht so.

(Und Ole hat bei einer sehr ähnlichen Konstruktion eine Fehlermeldung
bekommen, aber vielleicht hat er nicht den gcc verwendet. clang per
default, gcc nur bei -pedantic).

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Оlе Ѕtrеісhеr
2017-09-11 20:20:50 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Florian Weimer
Bei GNU CC sorgt die erste Konstruktion dafür, daß die
Funktionsdefinition als
| int
| tcsetpgrp (int fd, pid_t pgrp_id)
| {
| …
| }
übersetzt wird, d.h. der Prototyp ändert auch das Verhalten der
Definition.
Oh, das ist mir neu. War früher (vor ca. 1995) meiner Erinnerung nach
nicht so.
(Und Ole hat bei einer sehr ähnlichen Konstruktion eine Fehlermeldung
bekommen, aber vielleicht hat er nicht den gcc verwendet. clang per
default, gcc nur bei -pedantic).
gcc 7.2.0 (aus Debian testing). Ohne -pedantic

Die Frage bleibt aber noch: soweit ich das bisher verfolgt habe, ist
(nur) das Problem, dass der Prototyp das Verhalten ändert, man also eine
Definition ohne Prototyp nicht mit einer Verwendeung mit deklariertem
Prototyp mixen kann.

Aber, der simple Fall wäre ja, dass man Prototypen konsequent einführt;
also sowohl in der Definition einen Prototypen verwendet als auch eine
entsprechende Deklaration vor der Anwendung. Wäre das irgendwo
problematisch?

In diesem Fall wäre dann doch ein "protoize" sehr trivial möglich mit

TYPE1 func (); // declaration

TYPE1 func ()
TYPE2 foo;
TYPE3 bar;
{...}

in

TYPE1 func (TYPE2 foo, TYPE3 bar); // declaration
TYPE1 func (TYPE2 foo, TYPE3 bar) {...}

Warum gibt/gab es dafür keine tools? Oder übersehe ich da wieder eine
Komplikation?

Schöne Grüße

Ole
Florian Weimer
2017-09-12 13:43:41 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Aber, der simple Fall wäre ja, dass man Prototypen konsequent einführt;
also sowohl in der Definition einen Prototypen verwendet als auch eine
entsprechende Deklaration vor der Anwendung. Wäre das irgendwo
problematisch?
Solange die Prototypen stimmen, funktioniert es.
Post by Оlе Ѕtrеісhеr
Warum gibt/gab es dafür keine tools? Oder übersehe ich da wieder eine
Komplikation?
Üblicherweise wollte man ja gar nicht auf C89 wechseln. Außerdem war
es einst sehr verbreitet, den Anfang von Funktionsdefinitionen per
Makro zu machen (DEFUN usw.).
Оlе Ѕtrеісhеr
2017-09-12 15:14:22 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Оlе Ѕtrеісhеr
Aber, der simple Fall wäre ja, dass man Prototypen konsequent einführt;
also sowohl in der Definition einen Prototypen verwendet als auch eine
entsprechende Deklaration vor der Anwendung. Wäre das irgendwo
problematisch?
Solange die Prototypen stimmen, funktioniert es.
Post by Оlе Ѕtrеісhеr
Warum gibt/gab es dafür keine tools? Oder übersehe ich da wieder eine
Komplikation?
Üblicherweise wollte man ja gar nicht auf C89 wechseln.
Warum nicht?

Solange noch nicht alles Compiler ANSI konnte, ist das ja einzusehen,
aber spätestens so Mitte der 90er war das sicher kein allgemeines
Argument mehr. Und selbst konnte man das ja mit entsprechenden Macros
armieren.
Post by Florian Weimer
Außerdem war es einst sehr verbreitet, den Anfang von
Funktionsdefinitionen per Makro zu machen (DEFUN usw.).
DEFUN sagt mir nichts, -v bitte.

Wenn ich mir Code aus damaligen Zeiten anschaue, dann sieht der mir auch
meist ganz profan aus, was den Funktionskopf betrifft: halt entweder mit
Prototypen oder ohne (oder mit beidem je nach #define).

Schöne Grüße

Ole
Florian Weimer
2017-09-12 17:30:16 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Florian Weimer
Üblicherweise wollte man ja gar nicht auf C89 wechseln.
Warum nicht?
Solange noch nicht alles Compiler ANSI konnte, ist das ja einzusehen,
aber spätestens so Mitte der 90er war das sicher kein allgemeines
Argument mehr. Und selbst konnte man das ja mit entsprechenden Macros
armieren.
Doch. Es gab mehrere große Hersteller, die kostenlos einen
K&R-Compiler bereitstellten, aber für C89/C90 extra Geld verlangten.
Post by Оlе Ѕtrеісhеr
Post by Florian Weimer
Außerdem war es einst sehr verbreitet, den Anfang von
Funktionsdefinitionen per Makro zu machen (DEFUN usw.).
DEFUN sagt mir nichts, -v bitte.
Die K&R-Variante sieht so aus:

| DEFUN ("numberp", Fnumberp, Snumberp, 1, 1, 0,
| "T if OBJECT is a number (floating point or integer).")
| (obj)
| Lisp_Object obj;
| {
| if (XTYPE (obj) == Lisp_Float || XTYPE (obj) == Lisp_Int)
| return Qt;
| return Qnil;
| }

Heutzutage sieht es so aus:

| DEFUN ("numberp", Fnumberp, Snumberp, 1, 1, 0,
| doc: /* Return t if OBJECT is a number (floating point or integer). */
| attributes: const)
| (Lisp_Object object)
| {
| if (NUMBERP (object))
| return Qt;
| else
| return Qnil;
| }

Refactoring von C-Code ist generell schwierig.
Оlе Ѕtrеісhеr
2017-09-12 20:20:00 UTC
Permalink
Raw Message
Post by Florian Weimer
Post by Оlе Ѕtrеісhеr
Post by Florian Weimer
Üblicherweise wollte man ja gar nicht auf C89 wechseln.
Warum nicht?
Solange noch nicht alles Compiler ANSI konnte, ist das ja einzusehen,
aber spätestens so Mitte der 90er war das sicher kein allgemeines
Argument mehr. Und selbst konnte man das ja mit entsprechenden Macros
armieren.
Doch. Es gab mehrere große Hersteller, die kostenlos einen
K&R-Compiler bereitstellten, aber für C89/C90 extra Geld verlangten.
Wie schon gesagt: selbst dann kann man ja Macros nehmen, die beides leisten.
Post by Florian Weimer
Post by Оlе Ѕtrеісhеr
Post by Florian Weimer
Außerdem war es einst sehr verbreitet, den Anfang von
Funktionsdefinitionen per Makro zu machen (DEFUN usw.).
DEFUN sagt mir nichts, -v bitte.
| DEFUN ("numberp", Fnumberp, Snumberp, 1, 1, 0,
| "T if OBJECT is a number (floating point or integer).")
| (obj)
| Lisp_Object obj;
Das sieht mich nicht gerade "sehr verbeitet" aus, auch damals
nicht. Sondern eher spezifisch im Lisp-Umfeld. Und für diesen Fall wäre
ein entsprechender Lisp-Code zum Refaktoring wohl auch nicht wahnsinning
kompliziert gewesen.
Post by Florian Weimer
Refactoring von C-Code ist generell schwierig.
Also mein konkretes Problem wäre mit einem primitiven K&R-Parser zu
lösen gewesen -- nicht einmal includes hätte es prozessieren müssen. Und
der Code ist sicher nicht untypisch für die damaligen Verhältnisse.

Schöne Grüße

Ole
Peter J. Holzer
2017-09-13 16:39:08 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Die Frage bleibt aber noch: soweit ich das bisher verfolgt habe, ist
(nur) das Problem, dass der Prototyp das Verhalten ändert, man also eine
Definition ohne Prototyp nicht mit einer Verwendeung mit deklariertem
Prototyp mixen kann.
Aber, der simple Fall wäre ja, dass man Prototypen konsequent einführt;
also sowohl in der Definition einen Prototypen verwendet als auch eine
entsprechende Deklaration vor der Anwendung. Wäre das irgendwo
problematisch?
In diesem Fall wäre dann doch ein "protoize" sehr trivial möglich mit
TYPE1 func (); // declaration
TYPE1 func ()
TYPE2 foo;
TYPE3 bar;
{...}
in
TYPE1 func (TYPE2 foo, TYPE3 bar); // declaration
TYPE1 func (TYPE2 foo, TYPE3 bar) {...}
Warum gibt/gab es dafür keine tools? Oder übersehe ich da wieder eine
Komplikation?
cproto macht das (mit -a) doch? Und protoize macht nach Meinung
mindestens einer Person in diesem Thread *nur* das und nicht die andere
Variante.

Um das allerdings 100% zuverlässig machen zu können, muss man C richtig
parsen können. Das erfordert jedenfalls einen Präprozessor und einen
C-Parser. Als Präprozessor kann man vermutlich nicht einfach cpp
verwenden, weil man dann ja nicht mehr den Originalsource-Code hat, den
man umschreiben will, sondern den präprozessierten. Man braucht einen,
der sich in den Parser so integriert, dass sowohl der
Original-Source-Code als auch der Syntax-Tree rauskommen. Das ist
jedenfalls kein schneller Hack mehr, sondern eher ein Drittel eines
ganzen Compilers oder so. Und selbst dann gibt es sicher ein paar
Präprozessor-Tricks in freier Wildbahn, an denen auch das scheitert.
Also werden diese Tools wohl eher mit einer vereinfachten Heuristik
arbeiten, die halt nur 95% schafft.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Оlе Ѕtrеісhеr
2017-09-13 18:45:34 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Оlе Ѕtrеісhеr
In diesem Fall wäre dann doch ein "protoize" sehr trivial möglich mit
TYPE1 func (); // declaration
TYPE1 func ()
TYPE2 foo;
TYPE3 bar;
{...}
in
TYPE1 func (TYPE2 foo, TYPE3 bar); // declaration
TYPE1 func (TYPE2 foo, TYPE3 bar) {...}
Warum gibt/gab es dafür keine tools? Oder übersehe ich da wieder eine
Komplikation?
cproto macht das (mit -a) doch? Und protoize macht nach Meinung
mindestens einer Person in diesem Thread *nur* das und nicht die andere
Variante.
Nach meinem Test hat es sich ab und zu an den diversen #includes
verschluckt und sich dann geweigert, umzustellen. Genau das hatte mich
gewundert.
Post by Peter J. Holzer
Um das allerdings 100% zuverlässig machen zu können, muss man C richtig
parsen können. Das erfordert jedenfalls einen Präprozessor und einen
C-Parser.
Das ist ja genau mein Punkt: wozu der Preprozessor? Die obige Umstellung
ist doch lokal; wozu muss man dort die Includes einlesen?

Schöne Grüße

Ole
Peter J. Holzer
2017-09-14 19:14:27 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Um das allerdings 100% zuverlässig machen zu können, muss man C richtig
parsen können. Das erfordert jedenfalls einen Präprozessor und einen
C-Parser.
Das ist ja genau mein Punkt: wozu der Preprozessor? Die obige Umstellung
ist doch lokal; wozu muss man dort die Includes einlesen?
Zum Beispiel, um Typdefinitionen zu bekommen. Ohne zu wissen, ob ein
Identifier ein Typname ist oder etwas anderes, kannst Du keine
C-Deklarationen parsen.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Florian Weimer
2017-09-12 13:39:29 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Florian Weimer
Post by Peter J. Holzer
Post by Florian Weimer
Die Frage ist halt, ob jemand sich die Mühe gemacht hat, das ganze
tatsächlich richtig umzustellen, so daß der Code auch noch auf
nicht-GNU-C89-Compilern läuft oder seltsamen ABIs wie POWER ELFv2.
Viele GNU-Projekte nutzen Prototypen mit nicht exakt passenden
Funktionsdefinitionen im alten Stil, und das ist nunmal nicht
portabel. Deswegen wird das __P-Makro verwendet, damit man die
Prototypen bei Bedarf wieder loswerden kann.
Meiner Meinung nach nein: Das __P-Makro war dafür da, den Code mit einem
Compiler, der keine Prototypen versteht, kompilieren zu können.
Das Problem ist, daß
| extern int tcsetpgrp (int, pid_t);
|
| int
| tcsetpgrp (fd, pgrp_id)
| int fd;
| pid_t pgrp_id;
| {
| …
| }
eine GNU-Erweiterung ist. Andere C89-Compiler quittieren das mit einem
Fehler, weil sie hier als Prototyp
extern int tcsetpgrp (long, long);
erwarten, damit die Aufrufkonvention dem Nicht-Prototyp-Fall
entspricht. (Das ist m.E. das, was auch die C-Norm fordert.)
Sorry, aber das ist schlicht ein Unsinn, und ich habe bereits mindestens
zwei Mal in diesem Thread gepostet, was der C-Standard wirklich
vorsieht. Hier zum dritten Mal, diesmal mit Zitaten (aus C99, weil ich
Ja, mein Fehler, zumindest was C99 angeht. Mit float und double sollte
das aber stimmen.
Post by Peter J. Holzer
Post by Florian Weimer
Bei GNU CC sorgt die erste Konstruktion dafür, daß die
Funktionsdefinition als
| int
| tcsetpgrp (int fd, pid_t pgrp_id)
| {
| …
| }
übersetzt wird, d.h. der Prototyp ändert auch das Verhalten der
Definition.
Oh, das ist mir neu. War früher (vor ca. 1995) meiner Erinnerung nach
nicht so.
Ich glaube nicht, daß GNU CC das Verhalten geändert hat. Es ist aber
definitiv eine GNU-Erweiterung.
Peter J. Holzer
2017-09-08 20:00:42 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Äh, es gibt allen Ernstes, C-Programmierer, die im Jahr 2017 Code ohne
Prototypen weiterpflegen?
Sagen wir mal: der letzte Patch mit einem Versuch (nicht von mir),
Prototypen einzufügen stammt aus dem Jahr 2009. Vom Autor ignoriert.
Post by Peter J. Holzer
Ich dachte, Ole hätte da irgendwelchen Code ausgegraben, den sich seit
mindestens 20 Jahren kein Mensch mehr angeschaut hat.
https://github.com/iraf/iraf-v216
Der ist (teilweise) >30 Jahre alt, aber immer noch in Verwendung. Heute
Legacy (IMO aufgrund der Ignoranz der Autoren), und die Pflege kann man
nicht mehr unbedingt als "liebevoll" bezeichnen.
Post by Peter J. Holzer
Post by Rainer Weikusat
Und was ist das Problem damit?
Dass man aus der Einstellung dieser Programmierer durchaus Schlüsse auf
ihre Kompetenz und die Qualität ihres Codes ziehen sollte.
Das ist halt so ein Problem. Was bei einer Festanstellung auf Lebenszeit
dann zu einem PAL wird.
[...]
[...]
Post by Оlе Ѕtrеісhеr
Da können die alten Herrschaften nicht mehr mithalten, und man kann
halt nur hoffen, dass sie irgendwann in Rente gehen.
In den 90er-Jahren waren die alten Herrschaften aber noch nicht ganz so
alt.
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Es ist lange her, dass ich sowas gebraucht habe, aber meiner Erinnerung
gab es in den 90er-Jahren Tools, die genau das gemacht haben: C-Code in
K&R-Syntax geparst und daraus ein Header-File mit Deklarationen mit
Prototypen generiert. Vermutlich ... ach, was soll ich lang
herumspekulieren, ich installiere jetzt einfach cproto und lese die
Man-Page. Yup, cproto macht das per default.
Sender Jerewan, zumindest in meinem Fall: bei Hin- und Her-Definitionen
(Funktionsnamen, Typen mit #define etc.) kommt das Ding gerne mal
durcheinander und verweigert die Erstellung des Prototypen. Gcc kann
sowas ähnliches auch (mittels -aux-file=), aber löst dabei gnadenlos
alle #defines auf und ist damit unbrauchbar.
Letztlich habe ich cproto genommen, dann bei gcc die entsprechenden
Optionen angeschaltet (-Wold-style-definition & Co.) und dann den Rest
per Hand umgestellt. Effektives Arbeiten ist was anderes...
Effektiv ist etwas, wenn es den gewünschten Effekt hat. Effizient ist
etwas, wenn das Verhältnis von Aufwand zu Wirkung minimal ist.
Post by Оlе Ѕtrеісhеr
Protoize aus gcc-4.? ist da übrigens auch nicht besser. Es ist schon
erstaunlich, warum so eine recht überschaubare Aufgabe nicht allgemein
fehlerfrei zu lösen ist.
Die Aufgabe ist im allgemeinen unlösbar. Es gibt (m.E.) für jede
Plattform eine technisch korrekte Lösung, aber die kann bei
verschiedenen Plattforman unterschiedlich sein. Und keine dieser
Lösungen ist notwendigerweise semantisch korrekt. Im Fall von
Konflikten muss man dann entscheiden, was wichtiger ist.

Cproto und Konsorten kann man daher auf zwei Arten verwenden:

1) Als Tool zur Unterstützung bei der Umstellung einer Code-Basis. Da
ist es schon eine große Hilfe, wenn der Großteil automatisch erledigt
wird und man sich nur mehr um die Ausnahmen kümmern muss.

2) Zur vollautomatischen Konvertierung, wenn das Ergebnis nur zur
Weiterverarbeitung durch einen bestimmten Compiler bestimmt ist und
weder portabel noch lesbar sein muss.

Das sind recht unterschiedliche Anwendungsfälle, und es ist möglich,
dass ein bestimmtes Tool nur für einen der beiden Anwendungsfälle
geeignet ist. Ich habe in den 90er-Jahren cproto (ich glaube, es war
cproto, ist lange her) hauptsächlich für Zweck 1 verwendet. Protoize war
von gcc wohl hauptsächlich für Zweck 2 vorgesehen.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Оlе Ѕtrеісhеr
2017-09-08 20:50:59 UTC
Permalink
Raw Message
Post by Peter J. Holzer
[...]
[...]
Post by Оlе Ѕtrеісhеr
Da können die alten Herrschaften nicht mehr mithalten, und man kann
halt nur hoffen, dass sie irgendwann in Rente gehen.
In den 90er-Jahren waren die alten Herrschaften aber noch nicht ganz so
alt.
In den 90ern waren automatische Tests und die anderen heutigen
Selbstverständlichkeiten aber auch noch nicht so selbstverständlich.
Post by Peter J. Holzer
Post by Оlе Ѕtrеісhеr
Protoize aus gcc-4.? ist da übrigens auch nicht besser. Es ist schon
erstaunlich, warum so eine recht überschaubare Aufgabe nicht allgemein
fehlerfrei zu lösen ist.
Die Aufgabe ist im allgemeinen unlösbar. Es gibt (m.E.) für jede
Plattform eine technisch korrekte Lösung, aber die kann bei
verschiedenen Plattforman unterschiedlich sein. Und keine dieser
Lösungen ist notwendigerweise semantisch korrekt. Im Fall von
Konflikten muss man dann entscheiden, was wichtiger ist. [...]
Um das ganze wieder man On-Topic werden zu lassen: Ich dachte immer,
protoize macht aus

TYPE0 foo ()
TYPE1 arg1;
TYPE2 arg2;
{ /*body */ }

einfach

TYPE0 foo (
TYPE1 arg1,
TYPE2 arg2
)
{ /*body */ }


(wenn man variable Argumentlisten mal außen vor lässt). Das sieht mir
erstmal sehr mechanisch aus. Daraus noch Prototypen zu basteln, sollte
auch kein großes Problem sein.

Zumindest würde ich so von Hand vorgehen.

Wo ist da mein Denkfehler?

Schöne Grüße

Ole
Peter J. Holzer
2017-09-09 09:05:36 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
[...]
[...]
Post by Оlе Ѕtrеісhеr
Da können die alten Herrschaften nicht mehr mithalten, und man kann
halt nur hoffen, dass sie irgendwann in Rente gehen.
In den 90er-Jahren waren die alten Herrschaften aber noch nicht ganz so
alt.
In den 90ern waren automatische Tests und die anderen heutigen
Selbstverständlichkeiten aber auch noch nicht so selbstverständlich.
Wir reden hier konkret von Prototypen. Die wurden offiziell 1989
eingeführt. Einige Compiler verstanden sie schon vorher, andere erst
später, aber ab 1995 sollte es für jede Plattform mindestens einen
Compiler gegeben haben, der Prototypen versteht. Und selbst, wenn man
Kompatibilität mit K&R-Compilern erhalten wollte, war das mit geringem
Mehraufwand möglich, und man hatte trotzdem die Vorteile von Prototypen.

Ich habe natürlich keine Statistiken über die Verwendung von Prototypen,
aber aus meiner Erinnerung an mein Umfeld und Open Source Software[1]
dieser Zeit traue ich mich zu sagen, dass die Verwendung von Prototypen
damals selbstverständlich war und die Nicht-Verwendung von Prototypen
damals schon gewisse Zweifel an der Kompetenz eines C-Programmierers
aufkommen ließ.
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Post by Оlе Ѕtrеісhеr
Protoize aus gcc-4.? ist da übrigens auch nicht besser. Es ist schon
erstaunlich, warum so eine recht überschaubare Aufgabe nicht allgemein
fehlerfrei zu lösen ist.
Die Aufgabe ist im allgemeinen unlösbar. Es gibt (m.E.) für jede
Plattform eine technisch korrekte Lösung, aber die kann bei
verschiedenen Plattforman unterschiedlich sein. Und keine dieser
Lösungen ist notwendigerweise semantisch korrekt. Im Fall von
Konflikten muss man dann entscheiden, was wichtiger ist. [...]
Um das ganze wieder man On-Topic werden zu lassen: Ich dachte immer,
protoize macht aus
TYPE0 foo ()
TYPE1 arg1;
TYPE2 arg2;
{ /*body */ }
einfach
TYPE0 foo (
TYPE1 arg1,
TYPE2 arg2
)
{ /*body */ }
(wenn man variable Argumentlisten mal außen vor lässt). Das sieht mir
erstmal sehr mechanisch aus. Daraus noch Prototypen zu basteln, sollte
auch kein großes Problem sein.
Ich meinte den Fall, wo nur passende Deklarationen erzeugt werden, nicht
die Definitionen umgeschrieben (das war damals meiner Meinung nach die
übliche Anwendung, da man den Code ja weiterhin mit einem K&R-Compiler
compilieren können wollte).

Dann ist es im Allgemeinen falsch, aus der Definition

TYPE0 foo (arg1, arg2)
TYPE1 arg1;
TYPE2 arg2;
{
/*body */
}

die Deklaration

TYPE0 foo(TYPE1 arg1, TYPE2 arg2);

zu generieren. Die ist nicht kompatibel zur Definition. Wenn TYPE1 z.B.
unsigned short ist, dann ist der korrekte Typ im Prototyp entweder int
oder unsigned int. Welches von beiden, hängt davon ab, ob short kürzer
als int ist (dann ist der korrekte Typ int) oder gleich lang (dann ist
der korrekte Typ unsigned int). Um den korrekten Prototypen zu
produzieren, muss protoize nicht nur die Definition von TYPE1 kennen,
sondern auch noch Implementationsdetails der Zielplattform. Ein
portables Ergebnis (also eines, das sich auf jeder Plattform kompilieren
lässt), ist in diesem Fall unmöglich. Das war insbesondere dann ein
Problem, wenn TYPE1 ein vom Betriebssystem definierter Typ war und man
nur wusste, dass "an integral type" sei. Meist gab es eine Lösung, aber
die erforderte menschliche Intelligenz und oft Änderungen anderswo im
Code, das ging nicht automatisch.

hp

[1] Ja, ich weiß, den Begriff gab es damals noch nicht.
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Оlе Ѕtrеісhеr
2017-09-09 12:38:57 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Ich meinte den Fall, wo nur passende Deklarationen erzeugt werden, nicht
die Definitionen umgeschrieben (das war damals meiner Meinung nach die
übliche Anwendung, da man den Code ja weiterhin mit einem K&R-Compiler
compilieren können wollte).
Dann ist es im Allgemeinen falsch, aus der Definition
TYPE0 foo (arg1, arg2)
TYPE1 arg1;
TYPE2 arg2;
{
/*body */
}
die Deklaration
TYPE0 foo(TYPE1 arg1, TYPE2 arg2);
zu generieren. Die ist nicht kompatibel zur Definition. Wenn TYPE1 z.B.
unsigned short ist, dann ist der korrekte Typ im Prototyp entweder int
oder unsigned int. Welches von beiden, hängt davon ab, ob short kürzer
als int ist (dann ist der korrekte Typ int) oder gleich lang (dann ist
der korrekte Typ unsigned int).
Warum?

Ich hätte immer gedacht, dass

int foo(unsigned short i, unsigned short j);

eine korrekte standardkonforme Prototypendeklaration ist. Kannst Du ein
Beispiel nennen, wann die beiden nicht kompatibel sind?

Schöne Grüße

Ole
Peter J. Holzer
2017-09-09 18:56:17 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Ich meinte den Fall, wo nur passende Deklarationen erzeugt werden, nicht
die Definitionen umgeschrieben (das war damals meiner Meinung nach die
übliche Anwendung, da man den Code ja weiterhin mit einem K&R-Compiler
compilieren können wollte).
Dann ist es im Allgemeinen falsch, aus der Definition
TYPE0 foo (arg1, arg2)
TYPE1 arg1;
TYPE2 arg2;
{
/*body */
}
die Deklaration
TYPE0 foo(TYPE1 arg1, TYPE2 arg2);
zu generieren. Die ist nicht kompatibel zur Definition. Wenn TYPE1 z.B.
unsigned short ist, dann ist der korrekte Typ im Prototyp entweder int
oder unsigned int. Welches von beiden, hängt davon ab, ob short kürzer
als int ist (dann ist der korrekte Typ int) oder gleich lang (dann ist
der korrekte Typ unsigned int).
Warum?
Ich hätte immer gedacht, dass
int foo(unsigned short i, unsigned short j);
eine korrekte standardkonforme Prototypendeklaration ist.
Es ist eine standardkonforme Prototypendeklaration, aber nicht
diejenige, die kompatibel zur Definition

int foo(i, j)
unsigned short i;
unsigned short j;
{
...
}

ist. Bei einer K&R-Definitionen werden nämlich die "default argument
promotions" angewendet.

Diese K&R-Definition ist also äquivalent zu

int foo(int tmp_i, int tmp_j) {
unsigned short i = tmp_i;
unsigned short j = tmp_j;
...
}

(wenn USHORT_MAX <= INT_MAX, sonst haben die Parameter den Typ unsigned
int).

Eine Prototyp-Deklaration muss dazu kompatibel sein.

Die meisten Compiler werden einen Code, bei dem die Deklaration nicht
zur Definition passt, nicht compilieren. Und wenn man sie austrickst,
kann es sein, dass der kompilierte Code nicht funktioniert (weil der
Caller zwei 2-Byte-Argumente auf den Stack pusht, aber die Funktion
zwei 4-Byte-Argumente erwartet).

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Оlе Ѕtrеісhеr
2017-09-09 19:27:59 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Оlе Ѕtrеісhеr
Ich hätte immer gedacht, dass
int foo(unsigned short i, unsigned short j);
eine korrekte standardkonforme Prototypendeklaration ist.
Es ist eine standardkonforme Prototypendeklaration, aber nicht
diejenige, die kompatibel zur Definition
int foo(i, j)
unsigned short i;
unsigned short j;
{
...
}
ist. Bei einer K&R-Definitionen werden nämlich die "default argument
promotions" angewendet.
Diese K&R-Definition ist also äquivalent zu
int foo(int tmp_i, int tmp_j) {
unsigned short i = tmp_i;
unsigned short j = tmp_j;
...
}
(wenn USHORT_MAX <= INT_MAX, sonst haben die Parameter den Typ unsigned
int).
Eine Prototyp-Deklaration muss dazu kompatibel sein.
Mal ausprobieren:

--------------- foo.c --------8<----------------
#include <stdio.h>
int foo(a1, a2)
unsigned short a1;
int a2;
{
if (a1 != a2) {
printf("%i %i\n", (int)a1, a2);
return 0;
}
return 1;
}
--------------- foo.c --------8<----------------

--------------- bar.c --------8<----------------
int foo(unsigned short a1, int a2);

int main(void) {
int i, r = 1;
for (i = 0; r; i++)
r = foo(i, i);
return 0;
}
--------------- bar.c --------8<----------------

kompiliert und läuft bei mir prächtig. Ausgabe, wie zu erwarten
0 65536 (16-bit-short).

Wenn man beide Dateien kombiniert, meckert der Compiler tatsächlich über
conflicting types.
Post by Peter J. Holzer
Die meisten Compiler werden einen Code, bei dem die Deklaration nicht
zur Definition passt, nicht compilieren. Und wenn man sie austrickst,
kann es sein, dass der kompilierte Code nicht funktioniert (weil der
Caller zwei 2-Byte-Argumente auf den Stack pusht, aber die Funktion
zwei 4-Byte-Argumente erwartet).
Ich dachte, mal gelesen zu haben, das shorts als Funktionsparameter
immer in ein int (und float nach double) konvertiert werden?

Schöne Grüße

Ole
Peter J. Holzer
2017-09-09 20:37:16 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Post by Оlе Ѕtrеісhеr
Ich hätte immer gedacht, dass
int foo(unsigned short i, unsigned short j);
eine korrekte standardkonforme Prototypendeklaration ist.
Es ist eine standardkonforme Prototypendeklaration, aber nicht
diejenige, die kompatibel zur Definition
int foo(i, j)
unsigned short i;
unsigned short j;
{
...
}
ist. Bei einer K&R-Definitionen werden nämlich die "default argument
promotions" angewendet.
Diese K&R-Definition ist also äquivalent zu
int foo(int tmp_i, int tmp_j) {
unsigned short i = tmp_i;
unsigned short j = tmp_j;
...
}
(wenn USHORT_MAX <= INT_MAX, sonst haben die Parameter den Typ unsigned
int).
Eine Prototyp-Deklaration muss dazu kompatibel sein.
--------------- foo.c --------8<----------------
#include <stdio.h>
int foo(a1, a2)
unsigned short a1;
int a2;
{
if (a1 != a2) {
printf("%i %i\n", (int)a1, a2);
return 0;
}
return 1;
}
--------------- foo.c --------8<----------------
--------------- bar.c --------8<----------------
int foo(unsigned short a1, int a2);
int main(void) {
int i, r = 1;
for (i = 0; r; i++)
r = foo(i, i);
return 0;
}
--------------- bar.c --------8<----------------
kompiliert und läuft bei mir prächtig. Ausgabe, wie zu erwarten
0 65536 (16-bit-short).
Das ist genau das, was ich mit "Compiler austricksen" gemeint hatte: Du
hast die Definition in einer compilation unit, den Prototypen in einer
anderen. Der Compiler sieht also nie beide und kann nicht überprüfen, ob
sie konsistent sind. Er wird also einmal Code erzeugen, der zur
Definition passt, und einmal Code, der zum Prototypen passt. Das kann
gutgehen, muss aber nicht. (Im konkreten Fall wird es auf den meisten
modernen Plattformen wahrscheinlich gutgehen: Die ersten paar Parameter
werden in Registern übergeben und nicht mehr am Stack, und ein Register
hat nun einmal 64 Bit, auch wenn nur 16 davon gebraucht werden.)
Post by Оlе Ѕtrеісhеr
Wenn man beide Dateien kombiniert, meckert der Compiler tatsächlich über
conflicting types.
Standard-Methode ist, den Prototypen in ein Header-File zu schreiben,
und das sowohl im File mit der Definition und allen Files mit Aufrufen
zu inkludieren. Dann kann der Compiler sicherstellen, dass Definition
und Aufrufe konsistent sind.
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Die meisten Compiler werden einen Code, bei dem die Deklaration nicht
zur Definition passt, nicht compilieren. Und wenn man sie austrickst,
kann es sein, dass der kompilierte Code nicht funktioniert (weil der
Caller zwei 2-Byte-Argumente auf den Stack pusht, aber die Funktion
zwei 4-Byte-Argumente erwartet).
Ich dachte, mal gelesen zu haben, das shorts als Funktionsparameter
immer in ein int (und float nach double) konvertiert werden?
Nein. Das war in K&R-C so (Interessant, wie lange sich Fehlinformationen
halten). Mit der Einführung von Prototypen konnte C auch kleinere Typen
direkt übergeben. Manche Compiler haben das auch gemacht, insbesondere
bei float-Werten (bei 32-Bit-Maschinen (insbesondere RISC-Maschinen)
macht wes wenig Unterschied, ob man ein char als ein Byte oder ein Wort
übergibt, aber ob man ein Float als ein Wort oder zwei Worte übergibt
(samt Typumwandlung vorher und nachher), kann einen Unterschied machen).
Mittlerweile sind 64 Bit üblich, da wird wohl auf den meisten
Plattformen einfach alles in den passenden 64-Bit-Typ umgewandelt.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Rainer Weikusat
2017-09-10 15:32:37 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Оlе Ѕtrеісhеr
Post by Peter J. Holzer
Ich meinte den Fall, wo nur passende Deklarationen erzeugt werden, nicht
die Definitionen umgeschrieben (das war damals meiner Meinung nach die
übliche Anwendung, da man den Code ja weiterhin mit einem K&R-Compiler
compilieren können wollte).
Dann ist es im Allgemeinen falsch, aus der Definition
TYPE0 foo (arg1, arg2)
TYPE1 arg1;
TYPE2 arg2;
{
/*body */
}
die Deklaration
TYPE0 foo(TYPE1 arg1, TYPE2 arg2);
zu generieren. Die ist nicht kompatibel zur Definition.
[...]
Post by Peter J. Holzer
Post by Оlе Ѕtrеісhеr
Ich hätte immer gedacht, dass
int foo(unsigned short i, unsigned short j);
eine korrekte standardkonforme Prototypendeklaration ist.
Es ist eine standardkonforme Prototypendeklaration, aber nicht
diejenige, die kompatibel zur Definition
int foo(i, j)
unsigned short i;
unsigned short j;
{
...
}
ist. Bei einer K&R-Definitionen werden nämlich die "default argument
promotions" angewendet.
Diese K&R-Definition ist also äquivalent zu
int foo(int tmp_i, int tmp_j) {
unsigned short i = tmp_i;
unsigned short j = tmp_j;
...
}
(wenn USHORT_MAX <= INT_MAX, sonst haben die Parameter den Typ unsigned
int).
Das ist schon klar. Nur, was macht das fuer einen Unterschied wenn man -
wie protoize es tun wuerde - die Definition ebenfalls aendert?
Peter J. Holzer
2017-09-10 18:02:42 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Peter J. Holzer
Ich meinte den Fall, wo nur passende Deklarationen erzeugt werden, nicht
die Definitionen umgeschrieben (das war damals meiner Meinung nach die
übliche Anwendung, da man den Code ja weiterhin mit einem K&R-Compiler
compilieren können wollte).
[...]
Post by Rainer Weikusat
Das ist schon klar. Nur, was macht das fuer einen Unterschied wenn man -
wie protoize es tun wuerde - die Definition ebenfalls aendert?
Siehe oben. Der von mir gemeinte (und meiner Erinnerung nach Anfang der
90er-Jahre übliche) Anwendungsfall hat die Definition eben *nicht*
geändert, sondern nur passende Deklarationen produziert. Ob protoize das
kann, weiß ich nicht, ich habe damals glaube ich cproto verwendet.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Rainer Weikusat
2017-09-05 16:46:15 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist [...]
Wenn dem so *wäre*, warum wird dann Support für K&R C immer noch in den
gängigen Compilern mitgeschleppt? Das muss schließlich auch jemand betreuen.
Weil die C-Norm das fordert.
Es ist auch nicht wirklich sinnvoll, existierenden Code bloss
deswegen zu aendern, weil neuere Sprachfeatures fuer neugeschriebenen
Code irgendetwas einfacher machen (wenigstens hoffentlich).
Meiner Meinung nach ist "irgendetwas einfacher machen" ein sehr guter
Grund dafür, existierenden Code zu ändern.
Dann solltest Du C++ benutzen! Dort kann man ein Menschenleben damit
verbringen, den Fahradschuppen staendig neuzustreichen, damit er
weiterhin zeitgemaess aussieht (weswegen man nie dazu kommt, ein Fahrrad
reinzustellen, aber sowas stoert keinen grossen Geist :-).

Ich habe beruflich etwas mit "mixed-mode C" (K&R-Funktionsdefinitionen
plus bedingt uebersetzte Prototypen) zu tun. Insofern ich da neue
Unterroutine hinzufuege, bekommen die 'feste' Prototypen und
ANSI-Parameterdeklarationen, bei Aenderungen an K&R-Funktionen behalte
ich den Stil normalerweise bei. Funktionen die "einfach nur irgendwo
rumliegen" (und mutmasslich fuer etwas gut sind) lasse ich
grundsaetzlich in Ruhe. Das ist debuggter Code, der seit 20 Jahren
benutzt wird, warum sollte ich den aendern (und neu debuggen)?
Peter J. Holzer
2017-09-08 20:28:41 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Peter J. Holzer
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist [...]
Wenn dem so *wäre*, warum wird dann Support für K&R C immer noch in
den gängigen Compilern mitgeschleppt? Das muss schließlich auch
jemand betreuen.
Weil die C-Norm das fordert.
Es ist auch nicht wirklich sinnvoll, existierenden Code bloss
deswegen zu aendern, weil neuere Sprachfeatures fuer neugeschriebenen
Code irgendetwas einfacher machen (wenigstens hoffentlich).
Meiner Meinung nach ist "irgendetwas einfacher machen" ein sehr guter
Grund dafür, existierenden Code zu ändern.
Dann solltest Du C++ benutzen!
Weiche, Satan!
Post by Rainer Weikusat
Dort kann man ein Menschenleben damit verbringen, den Fahradschuppen
staendig neuzustreichen, damit er weiterhin zeitgemaess aussieht
Weiche nicht vom Thema ab: Du hast vorhin von "etwas einfacher machen"
geschrieben, nicht von modischer Farbgebung.

Eine Änderung, die die Arbeit erleichtert, amortisiert sich:
Schnellere Implementation, weniger Bugs. Weniger Zeit mit Fehlersuche
beschäftigt.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Rainer Weikusat
2017-09-09 18:06:47 UTC
Permalink
Raw Message
Post by Peter J. Holzer
Post by Rainer Weikusat
Post by Peter J. Holzer
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist [...]
Wenn dem so *wäre*, warum wird dann Support für K&R C immer noch in
den gängigen Compilern mitgeschleppt? Das muss schließlich auch
jemand betreuen.
Weil die C-Norm das fordert.
Es ist auch nicht wirklich sinnvoll, existierenden Code bloss
deswegen zu aendern, weil neuere Sprachfeatures fuer neugeschriebenen
Code irgendetwas einfacher machen (wenigstens hoffentlich).
Meiner Meinung nach ist "irgendetwas einfacher machen" ein sehr guter
Grund dafür, existierenden Code zu ändern.
Dann solltest Du C++ benutzen!
Weiche, Satan!
Post by Rainer Weikusat
Dort kann man ein Menschenleben damit verbringen, den Fahradschuppen
staendig neuzustreichen, damit er weiterhin zeitgemaess aussieht
Weiche nicht vom Thema ab: Du hast vorhin von "etwas einfacher machen"
geschrieben, nicht von modischer Farbgebung.
Schnellere Implementation, weniger Bugs. Weniger Zeit mit Fehlersuche
beschäftigt.
Ich hatte auch nicht 'modische Farbgebung' gemeint, sondern (relativ)
neue Features, die technisch nicht unbedingt erforderlich sind:
Funktionierender Code kann genausogut mit wie ohne Prototypen bereits
geschrieben worden sein. Ich wuerde keinen neuen C-Code ohne schreiben
wollen, aber zum Teil duerfte das auch bloss "Hamma schon imma so
gemacht!"-Gewohneit sein: Das C, das ich kenne, hatte 'schon immer'
Typueberpruefung von Funktionsargumenten.

Andererseits wuerde ich keine existierenden und funktionierenden Code
bloss deswegen aendern wollen, um Prototypen hinzuzufuegen: Das
unmittelbare Resultat wird ein jedem Fall einen Haufen Tippfehler
enthalten, die gefunden und korrigiert werden muessen, und
wahrscheinlich gaebe es dadurch auch ein paar neue semantische Fehler.

Solange dem Code weiter nichts fehlt, als das er altertuemlich aussieht,
wuerde ich ihn nicht anfassen.
Оlе Ѕtrеісhеr
2017-09-09 18:37:28 UTC
Permalink
Raw Message
Post by Rainer Weikusat
[...]
Solange dem Code weiter nichts fehlt, als das er altertuemlich aussieht,
wuerde ich ihn nicht anfassen.
Das Problem mit altem Code ist nach meiner Erfahrung das sogenannte
"bitrot": er funktioniert heute einfach nicht mehr. Beispiel hier wieder
IRAF, von den Autoren angepriesen als "portabel":

Der Code enthält sowohl Fortran- als auch C-Code, und eine eigene
Sprache, "SPP". Für die verschiedenen Variablentypen hat man
entsprechend auf diverse #defines gesetzt.

Mein erster Versuch, das mal auf 64 bit Big endian laufen zu lassen,
schlägt dann drastisch fehl: und zwar deshalb, weil als formaler
Argumenttyp ein Pointer auf einen 64-bit int verwendet wird, der
aktuelle Aufruf dann mit einem Pointer auf ein 32-bit int erfolgt. Das
klappt bei little endian (meistens), bei big endian dagegen nicht.

Das ist auch niemandem aufgefallen, weil es eben funktioniert hat. Und
weil die Funktion (wenn überhaupt) bestenfalls als "extern int ZCLSND()"
deklariert wurde (und zwar lokal, unmittelbar vor ihrem Aufruf!)

Das sieht nicht nur altertümlich aus, das ist auch einfach grottig. Die
beiden einzigen Möglichkeiten, sowas zu finden, sehe ich in Prototypen
und in Adress-Sanitizern.

Mir ist eigentlich kein größeres altes (>>20 Jahre) Programm bekannt,
welches nicht solche oder ähnlichen Probleme hätte. Zumindest in der
Astrophysik :-)

Freiwillig würde ich sowas auch nicht mehr mit der Kneifzange
anfassen. Wenn man es aber erhalten möchte...

Schöne Grüße

Ole
Rainer Weikusat
2017-09-11 13:37:10 UTC
Permalink
Raw Message
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
[...]
Solange dem Code weiter nichts fehlt, als das er altertuemlich aussieht,
wuerde ich ihn nicht anfassen.
Das Problem mit altem Code ist nach meiner Erfahrung das sogenannte
"bitrot": er funktioniert heute einfach nicht mehr. Beispiel hier wieder
[...]
Post by Оlе Ѕtrеісhеr
Mein erster Versuch, das mal auf 64 bit Big endian laufen zu lassen,
schlägt dann drastisch fehl: und zwar deshalb, weil als formaler
Argumenttyp ein Pointer auf einen 64-bit int verwendet wird, der
aktuelle Aufruf dann mit einem Pointer auf ein 32-bit int erfolgt. Das
klappt bei little endian (meistens), bei big endian dagegen nicht.
Naja, das ist jetzt ein Fehler, den der Compiler gefunden haette, wenn
die verwendete Sprache Typueberpruefung von Funktionsargumenten
unterstuetzen wuerde. Das das nicht der Fall ist, zieht natuerlich
Nachteile mit sich, andernfalls haette man das Feature gar nicht
eingefuehrt.

Aber den Fehler kann man sicher verbessern, ohne weite Teile des
Programms/ Softwaresystems, die mit diesem nicht zusammenhaengen,
umzuschreiben.
Post by Оlе Ѕtrеісhеr
Das ist auch niemandem aufgefallen, weil es eben funktioniert hat. Und
weil die Funktion (wenn überhaupt) bestenfalls als "extern int ZCLSND()"
deklariert wurde (und zwar lokal, unmittelbar vor ihrem Aufruf!)
Das sieht nicht nur altertümlich aus, das ist auch einfach grottig.
Warum ist das "einfach grottig"? Es ist in einer bestimmten
Programmiersprache geschrieben worden (K&R-C) die heutzutage nicht mehr
fuer Neuentwicklungen verwendet wird (soweit mir das bekannt ist). Diese
Programmiersprache unterstuetzt manches, was in ISO-C nicht gibt, zB
polymorhpe Funktionszeiger, und im Gegenzug fehlt ihr, was durch
Abschaffung dieser Features ermoeglicht wird, zB Typueberpruefung von
Funktionsargumenten.

Ich sehe hier bloss unterschiedliche Ansichten bzgl wuenschenswerter
tradeoffs, mehr Freiheit aber auch mehr Verantwortung fuer den
Programmierer versus bessere maschinenunterstuetzung seiner Arbeit, die
durch Einschraenkung der Ausdrucksfaehigkeit der Sprache erkauft wird.

Insofern solche Einschraenkungen umgangen werden koennen, falls das
notwendig ist, halte ich sie fuer sinnvoll (und das Fehlen solcher
Ueberpruefungen in Sprache wie Perl fuer ein grosses Aergernis), aber
andere Leute sehen das eben anders.
Оlе Ѕtrеісhеr
2017-09-11 14:21:02 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
[...]
Solange dem Code weiter nichts fehlt, als das er altertuemlich aussieht,
wuerde ich ihn nicht anfassen.
Das Problem mit altem Code ist nach meiner Erfahrung das sogenannte
"bitrot": er funktioniert heute einfach nicht mehr. Beispiel hier wieder
[...]
Post by Оlе Ѕtrеісhеr
Mein erster Versuch, das mal auf 64 bit Big endian laufen zu lassen,
schlägt dann drastisch fehl: und zwar deshalb, weil als formaler
Argumenttyp ein Pointer auf einen 64-bit int verwendet wird, der
aktuelle Aufruf dann mit einem Pointer auf ein 32-bit int erfolgt. Das
klappt bei little endian (meistens), bei big endian dagegen nicht.
Naja, das ist jetzt ein Fehler, den der Compiler gefunden haette, wenn
die verwendete Sprache Typueberpruefung von Funktionsargumenten
unterstuetzen wuerde. Das das nicht der Fall ist, zieht natuerlich
Nachteile mit sich, andernfalls haette man das Feature gar nicht
eingefuehrt.
Aber den Fehler kann man sicher verbessern, ohne weite Teile des
Programms/ Softwaresystems, die mit diesem nicht zusammenhaengen,
umzuschreiben.
Wenn man ihn denn mal gefunden hat, sicher. Und wenn man mal die Muße
hatte, das Ganze auf big endian zu kompilieren und sich über die
plötzlich auftauchenden Probleme wundert.

Der Fehler ist aber auch relevant auf little endian: und zwar genau
dann, wenn zufällig auf den restlichen bits irgendwelcher Müll
befindet. Das muss man dann nicht mal mitbekommen; es kann sein, dass
einfach das Ergebnis falsch ist (während die Tests bis dahin
durchlaufen).

Was würdest Du vorschlagen, um nach solchen Fehlerquellen zu suchen? Mir
fällt erstmal nichts besseres ein als Prototypen und Sanitizer.

Jedenfalls erscheint mir ein "Solange dem Code weiter nichts fehlt, als
das er altertuemlich aussieht, wuerde ich ihn nicht anfassen." als eine
recht "mutige" Argumentation. Selbst in >>30 Jahre altem Code, dessen
Reputation durch zahlreiche wissenschaftliche Publikationen gesichert
scheint. *Mein* Leben sollte besser nicht davon abhängen.
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Das ist auch niemandem aufgefallen, weil es eben funktioniert hat. Und
weil die Funktion (wenn überhaupt) bestenfalls als "extern int ZCLSND()"
deklariert wurde (und zwar lokal, unmittelbar vor ihrem Aufruf!)
Das sieht nicht nur altertümlich aus, das ist auch einfach grottig.
Warum ist das "einfach grottig"? Es ist in einer bestimmten
Programmiersprache geschrieben worden (K&R-C) die heutzutage nicht mehr
fuer Neuentwicklungen verwendet wird (soweit mir das bekannt ist). Diese
Programmiersprache unterstuetzt manches, was in ISO-C nicht gibt, zB
polymorhpe Funktionszeiger, und im Gegenzug fehlt ihr, was durch
Abschaffung dieser Features ermoeglicht wird, zB Typueberpruefung von
Funktionsargumenten.
Die Verwendung von Headerfiles war auch bei K&R möglich und üblich;
lokale externe Deklarationen (egal für was) anstelle von Headern stinkt
IMO einfach erbärmlich und war auch vor 30 Jahren nicht gerade
fortschrittlich.

Im übrigen handelt es sich dabei gar nicht um reines K&R-C -- manchmal
tauchen Prototypen auch durchaus auf. Da hätte man den Code durchaus
auch umschreiben können -- so groß ist der Aufwand dann nämlich auch
nicht (~100 Dateien, die meisten automatisch umstellbar).
Post by Rainer Weikusat
Ich sehe hier bloss unterschiedliche Ansichten bzgl wuenschenswerter
tradeoffs, mehr Freiheit aber auch mehr Verantwortung fuer den
Programmierer versus bessere maschinenunterstuetzung seiner Arbeit, die
durch Einschraenkung der Ausdrucksfaehigkeit der Sprache erkauft wird.
... und da ändern sich im Laufe der Jahrzehnte auch die Prioritäten. Was
vor 30 Jahren vielleicht noch als Kompromiss durchgegehen konnte, ist
heute einfach nur schlimm.

Es ist ja nicht so, dass ich den Quelltext in einem alten
Lochkartenstapel gefunden hätte. Er wird heutzutage noch produktiv
eingesetzt. Und der bis vor einigen Jahren auch noch aktiv entwickelt.

Schöne Grüße

Ole
Rainer Weikusat
2017-09-12 15:32:29 UTC
Permalink
Raw Message
[...]
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Mein erster Versuch, das mal auf 64 bit Big endian laufen zu lassen,
schlägt dann drastisch fehl: und zwar deshalb, weil als formaler
Argumenttyp ein Pointer auf einen 64-bit int verwendet wird, der
aktuelle Aufruf dann mit einem Pointer auf ein 32-bit int erfolgt. Das
klappt bei little endian (meistens), bei big endian dagegen nicht.
[...]
Post by Оlе Ѕtrеісhеr
Wenn man ihn denn mal gefunden hat, sicher. Und wenn man mal die Muße
hatte, das Ganze auf big endian zu kompilieren und sich über die
plötzlich auftauchenden Probleme wundert.
[...]
Post by Оlе Ѕtrеісhеr
Jedenfalls erscheint mir ein "Solange dem Code weiter nichts fehlt, als
das er altertuemlich aussieht, wuerde ich ihn nicht anfassen." als eine
recht "mutige" Argumentation. Selbst in >>30 Jahre altem Code, dessen
Reputation durch zahlreiche wissenschaftliche Publikationen gesichert
scheint.
Jedenfalls wurde der Fehler gefunden.

Um mal eine andere Geschichte zu erzaehlen: 'Manche Kunden' meines
Arbeitgebers sind sehr begeistert von neuer Hardware. Im konreten Fall
ist das ein Intel X710 40G NIC. Der ist zu neu, um von dem bis jetzt
benutzten Kernel unterstuetzt zu werden. Es gibt einen Treiber als
Quellcode-Download von Intel der angeblich alle Kernel seit 2.6.32
unterstuetzt. Das jetzt kein 'akademisches Softwarepaket', welches seit
den 80er-Jahren existiert und benutzt und sich mehr oder minder in
'emergency maintenance only'-Modus befindet, sondern eine offiziell
'unterstuetze' Software-Komponente, die zur Benutzung eines aktuellen
Intel-Produkts erforderlich ist.

In der Form, in der man den Treiber herunterladen kann, laesst er sich
in unserer Umgebung noch nicht mal kompilieren. Nach Beheben diese
Fehlers bekommt man dann ein kompiliertes Modul das einen sofortingen
Systemabsturz verurschacht, wenn man es zu laden
versucht. Hoechstwahrscheinlich ist das in dummer und laengst behobener
Fehler und es konnte sich nur niemand aufraffen, den veroeffentlichten Code
zu reparieren.

Diesbezueglich hat "ANSI-C" keine Wunder bewirkt.
Post by Оlе Ѕtrеісhеr
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Das ist auch niemandem aufgefallen, weil es eben funktioniert hat. Und
weil die Funktion (wenn überhaupt) bestenfalls als "extern int ZCLSND()"
deklariert wurde (und zwar lokal, unmittelbar vor ihrem Aufruf!)
Das sieht nicht nur altertümlich aus, das ist auch einfach grottig.
Warum ist das "einfach grottig"? Es ist in einer bestimmten
Programmiersprache geschrieben worden (K&R-C) die heutzutage nicht mehr
fuer Neuentwicklungen verwendet wird (soweit mir das bekannt ist). Diese
Programmiersprache unterstuetzt manches, was in ISO-C nicht gibt, zB
polymorhpe Funktionszeiger, und im Gegenzug fehlt ihr, was durch
Abschaffung dieser Features ermoeglicht wird, zB Typueberpruefung von
Funktionsargumenten.
Die Verwendung von Headerfiles war auch bei K&R möglich und üblich;
lokale externe Deklarationen (egal für was) anstelle von Headern stinkt
IMO einfach erbärmlich und war auch vor 30 Jahren nicht gerade
fortschrittlich.
Da waere ich jetzt mal sehr an einer Grund oder einer Menge von Gruenden
warum das "erbaermlich stinkt" interessiert, zumal in einer Sprache, die
keine Typ-Information in Funktionsdeklarationen unterstuetzt.

Wenn man die Deklaration in einem Header hat, ist es offensichtlich
einfacher, den Rueckgabewert von Funktionen zu aendern, weil das nur an
zwei Orten getan werden muss.

Andererseits wirft man durch einbeinden eines Headers im file scope eine
Menge Bezeichner in einen Namensraum, die dort gar nicht gebraucht
werden, waehrend lokale Deklarationen nur die sichtbar machen, die
tataechlich benoetigt werden, und auch nur in dem Rahmen, in dem sie
benoetigt werden.
Оlе Ѕtrеісhеr
2017-09-12 20:48:19 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Wenn man ihn denn mal gefunden hat, sicher. Und wenn man mal die Muße
hatte, das Ganze auf big endian zu kompilieren und sich über die
plötzlich auftauchenden Probleme wundert.
[...]
Post by Оlе Ѕtrеісhеr
Jedenfalls erscheint mir ein "Solange dem Code weiter nichts fehlt, als
das er altertuemlich aussieht, wuerde ich ihn nicht anfassen." als eine
recht "mutige" Argumentation. Selbst in >>30 Jahre altem Code, dessen
Reputation durch zahlreiche wissenschaftliche Publikationen gesichert
scheint.
Jedenfalls wurde der Fehler gefunden.
Und zwar dadurch, dass ich Prototypen eingeführt habe und dann lange in
der Jauche gewühlt, um auch alle Stellen zu erfassen.

Indem ich ihn *angefasst* habe. Indem ich das "ist portabel" einmal an
seine Grenzen gefahren habe.

Es ist *sinnvoll*, Code "anzufassen"; selbst wenn ihm scheinbar nichts
fehlt.
Post by Rainer Weikusat
Um mal eine andere Geschichte zu erzaehlen: [...]
Fehlers bekommt man dann ein kompiliertes Modul das einen sofortingen
Systemabsturz verurschacht, wenn man es zu laden
versucht. Hoechstwahrscheinlich ist das in dummer und laengst behobener
Fehler und es konnte sich nur niemand aufraffen, den veroeffentlichten Code
zu reparieren.
Diesbezueglich hat "ANSI-C" keine Wunder bewirkt.
So what? Ist ein Hammer sinnlos, nur weil man mit ihm keine Löcher
bohren kann?
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Die Verwendung von Headerfiles war auch bei K&R möglich und üblich;
lokale externe Deklarationen (egal für was) anstelle von Headern stinkt
IMO einfach erbärmlich und war auch vor 30 Jahren nicht gerade
fortschrittlich.
Da waere ich jetzt mal sehr an einer Grund oder einer Menge von Gruenden
warum das "erbaermlich stinkt" interessiert, zumal in einer Sprache, die
keine Typ-Information in Funktionsdeklarationen unterstuetzt.
Nicht für die Argumente, aber für den Rückgabewert. Eine als void
deklarierte Funktion kann halt nichts zurückgeben.
Post by Rainer Weikusat
Wenn man die Deklaration in einem Header hat, ist es offensichtlich
einfacher, den Rueckgabewert von Funktionen zu aendern, weil das nur an
zwei Orten getan werden muss.
... weil es *genau* an zwei wohlbestimmten Orten getan werden muss. Im
anderen Fall muss man nämlich den Rest des Quelltextes durchsuchen und
macht unentdeckte Fehler, wenn man eine Stelle vergisst.
Post by Rainer Weikusat
Andererseits wirft man durch einbeinden eines Headers im file scope eine
Menge Bezeichner in einen Namensraum, die dort gar nicht gebraucht
werden, waehrend lokale Deklarationen nur die sichtbar machen, die
tataechlich benoetigt werden, und auch nur in dem Rahmen, in dem sie
benoetigt werden.
Das ist in dem genannten Projekt tatsächlich auch ein Problem, weil dort
die libc (subset) "nachprogrammiert" ist, basierend auf Fortran, aber
mit den orginalen Funktionsnamen (und natürlich nicht immer ganz
kompatiblen Aufrufen) -- da ist "#include <stdlib.h>" ... ähem
abenteuerlich.

Dieser libc-Ersatz war aber auch schon vor 25 Jahren kritisiert; den
würde ich nicht als Argument für den Namensraum heranziehen.

Schöne Grüße

Ole
Thomas Jahns
2017-09-13 16:58:35 UTC
Permalink
Raw Message
Post by Rainer Weikusat
In der Form, in der man den Treiber herunterladen kann, laesst er sich
in unserer Umgebung noch nicht mal kompilieren. Nach Beheben diese
Fehlers bekommt man dann ein kompiliertes Modul das einen sofortingen
Systemabsturz verurschacht, wenn man es zu laden
versucht. Hoechstwahrscheinlich ist das in dummer und laengst behobener
Fehler und es konnte sich nur niemand aufraffen, den veroeffentlichten Code
zu reparieren.
Diesbezueglich hat "ANSI-C" keine Wunder bewirkt.
Dass Linux keine stabile Treiber-API hat könnte aber ein völlig von Prototypen
unabhängiger und ausreichender Grund sein.

Thomas
Rainer Weikusat
2017-09-13 18:40:33 UTC
Permalink
Raw Message
Post by Thomas Jahns
Post by Rainer Weikusat
In der Form, in der man den Treiber herunterladen kann, laesst er sich
in unserer Umgebung noch nicht mal kompilieren. Nach Beheben diese
Fehlers bekommt man dann ein kompiliertes Modul das einen sofortingen
Systemabsturz verurschacht, wenn man es zu laden
versucht. Hoechstwahrscheinlich ist das in dummer und laengst behobener
Fehler und es konnte sich nur niemand aufraffen, den veroeffentlichten Code
zu reparieren.
Diesbezueglich hat "ANSI-C" keine Wunder bewirkt.
Dass Linux keine stabile Treiber-API hat könnte aber ein völlig von
Prototypen unabhängiger und ausreichender Grund sein.
... oder so denkt man sich das wenigstens mancherorten ...

Lt Intel unterstuetzt der Treiber (wie ich bereits geschrieben hatte)
alle Kernelversionen seit 2.6.32. Und jede von denen hat "eine stabile
Treiber-API", dh, die sich nicht selbstaetig aendert.
Peter J. Holzer
2017-09-09 19:54:13 UTC
Permalink
Raw Message
Post by Rainer Weikusat
Post by Peter J. Holzer
Post by Rainer Weikusat
Post by Peter J. Holzer
Post by Rainer Weikusat
Post by Оlе Ѕtrеісhеr
Da K&R C eigentlich schon seit mehr als 25 Jahren obsolet ist [...]
Wenn dem so *wäre*, warum wird dann Support für K&R C immer noch in
den gängigen Compilern mitgeschleppt? Das muss schließlich auch
jemand betreuen.
Weil die C-Norm das fordert.
Es ist auch nicht wirklich sinnvoll, existierenden Code bloss
deswegen zu aendern, weil neuere Sprachfeatures fuer neugeschriebenen
Code irgendetwas einfacher machen (wenigstens hoffentlich).
Meiner Meinung nach ist "irgendetwas einfacher machen" ein sehr guter
Grund dafür, existierenden Code zu ändern.
Dann solltest Du C++ benutzen!
Weiche, Satan!
Post by Rainer Weikusat
Dort kann man ein Menschenleben damit verbringen, den Fahradschuppen
staendig neuzustreichen, damit er weiterhin zeitgemaess aussieht
Weiche nicht vom Thema ab: Du hast vorhin von "etwas einfacher machen"
geschrieben, nicht von modischer Farbgebung.
Schnellere Implementation, weniger Bugs. Weniger Zeit mit Fehlersuche
beschäftigt.
Ich hatte auch nicht 'modische Farbgebung' gemeint, sondern (relativ)
Naja, was ist schon "unbedingt erforderlich"? Man kann auch
funktionierenden Code in Assembler schreiben (habe ich sogar noch für
meine Diplomarbeit 1994 gemacht). Und einiger Code, mit dem ich
beruflich zu tun habe, zeigt, dass man so ziemlich alle Features
moderner Programmiersprachen (für großzügige Werte von "modern": Sowohl
Java als auch Python sind über 20 Jahre alt) ignorieren und trotzdem
funktionierenden Code produzieren kann.

Aber dieser Code ist halt schwer verständlich, unnötig kompliziert, und
er nützt die Möglichkeiten, die die Programmiersprache zur
Fehlervermeidung bietet, nicht aus. Dementsprechend funktioniert der
Code halt auch nicht immer. Und nach jeder Änderung ist die
Wahrscheinlichkeit, dass er immer noch funktioniert, ein wenig kleiner.

Da spare ich mir in Summe wirklich Zeit, wenn ich vor einer Änderung
erst mal refaktoriere. Vielleicht nicht für die eine Änderung, die ich
jetzt gerade mache, aber spätestens bei der nächsten oder übernächsten.

Ich muss weniger Code lesen, Fehler sind schneller gefixt, wenn der
Compiler schreit als die Testsuite, und scheller (und stressfreier),
wenn die Testsuite schreit als der Kunde.

Schon klar, das muss in einem gewissen Verhältnis zum Zweck stehen: Um
eine Änderung von 2 Zeilen vorzunehmen, refaktoriere ich keine
30000-Zeilen-Java-Klasse, wahrscheinlich nicht mal die
1000-Zeilen-Methode, in der ich das Ändern muss. Aber wenn ich diese 2
Zeilen in der Methode 20 mal ändern muss, ist die Wahrscheinlichkeit
groß, dass es anschließend 10 50-Zeilen-Methoden sind (ups, der Code ist
nur noch halb so lang? Na sowas!)
Post by Rainer Weikusat
Funktionierender Code kann genausogut mit wie ohne Prototypen bereits
geschrieben worden sein. Ich wuerde keinen neuen C-Code ohne schreiben
wollen, aber zum Teil duerfte das auch bloss "Hamma schon imma so
gemacht!"-Gewohneit sein: Das C, das ich kenne, hatte 'schon immer'
Typueberpruefung von Funktionsargumenten.
Ich bin offenbar ein paar Jahre älter als Du und habe noch zu K&R-Zeiten
mit der C-Programmierung begonnen. Das ging natürlich, aber einige der
Bugs waren ... interessant, und Prototypes waren eine große Hilfe
(andererseits gab es auch vorher schon lint).

Andererseits verwende ich bevorzugt Programmiersprachen mit dynamischem
Typsystem (Perl und Python). Da gibt es Typüberprüfungen bestenfalls zur
Laufzeit. Also insofern lebe ich immer noch ganz gut ohne
Typüberprüfungen, aber das Runtime-System dieser Sprachen ist halt auch
total anders, also sind die damit verbundenen Klassen von Bugs andere.
Post by Rainer Weikusat
Andererseits wuerde ich keine existierenden und funktionierenden Code
bloss deswegen aendern wollen, um Prototypen hinzuzufuegen: Das
unmittelbare Resultat wird ein jedem Fall einen Haufen Tippfehler
enthalten, die gefunden und korrigiert werden muessen, und
wahrscheinlich gaebe es dadurch auch ein paar neue semantische Fehler.
Wie bereits geschrieben, war mein Ansatz damals in den 90er-Jahren,
mittels cproto ein Header-File zu erzeugen, das ich dann inkludiert
habe. Die Erzeugung war automatisch, also keine Tippfehler möglich.
Semantische Fehler (z.B. wegen nicht korrekt erkannter Argument
Promotion) hat meistens der Compiler erkannt und die musste ich dann
halt händisch ausbessern. Bei den Code-Größen damals kein großer
Aufwand.
Post by Rainer Weikusat
Solange dem Code weiter nichts fehlt, als das er altertuemlich aussieht,
wuerde ich ihn nicht anfassen.
Wenn dem Code nichts fehlt, habe ich meistens nicht einmal einen Grund,
ihn mir anzusehen. Da kann er aussehen, wie er will.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Loading...