Hallo zusammen. Ich übergebe einer Funktion einen Pointer auf eine Variable (in C). Wenn diese Variable noch keinen gültigen Wert erhalten hat (z.B. Variable enthält letzten Messwert, es wurde aber noch keine Messung durchgeführt), würde ich das gerne meiner Funktion mitteilen. Also, so dachte ich mir, übergebe ich einen NULL-Pointer, der ja in C auf die Adresse 0 zeigt. Ich frage mich nun, ob (bzw. warum) es ausgeschlossen ist, dass sich eine Variable tatsächlich an der Adresse 0 befindet. Für einen kleinen Hinweis wäre ich dankbar.
:
Verschoben durch Admin
futz schrieb: > Ich frage mich nun, ob (bzw. warum) es ausgeschlossen ist, dass sich > eine Variable tatsächlich an der Adresse 0 befindet. Z.B. beim 8051 ist das möglich, da er getrennte Daten- und Codezugriffe hat. Ich habe daher dem Linker gesagt, daß XDATA an der Adresse 0x0001 beginnt. Das eine Byte ungenutzter SRAM kann man verschmerzen.
:
Bearbeitet durch User
Man verwendet NULL oder nullptr. Der Compiler und die Architektur legen dann fest, was sich wirklich hinter dem Wert verbirgt. Das muss nicht ungedingt 0 sein.
PittyJ schrieb: > Man verwendet NULL oder nullptr. nullptr ist C++. PittyJ schrieb: > Der Compiler und die Architektur legen dann fest, was sich wirklich > hinter dem Wert verbirgt. Das muss nicht ungedingt 0 sein. Der Standard legt fest, dass NULL effektiv als (void*)0 definiert ist.
Je nach Rechner-Architektur ist an Adresse 0 "nichts", genauer wenn es virtuelle Speicherverwaltung gibt wird die Page 0 (z.B. 4096Bytes) als "nicht existent" markiert, oder Überraschendes, z.B. bei AVR (zumindest denen, die ich kenne) die CPU-Register. *(uint8_t*)0 -> R0; *(uint8_t*)1 -> R1; ...
Carl D. schrieb: > Je nach Rechner-Architektur ist an Adresse 0 > "nichts", genauer wenn es virtuelle Speicherverwaltung gibt wird die > Page 0 (z.B. 4096Bytes) als "nicht existent" markiert, > oder Überraschendes, z.B. bei AVR (zumindest denen, die ich kenne) die > CPU-Register. *(uint8_t*)0 -> R0; *(uint8_t*)1 -> R1; ... Ist das für deinen Compiler (AVR gcc?) dokumentiert? *(uint8_t*)0 sieht für mich ziemlich nach UB aus, da ein Null-Pointer dereferenziert wird (wenn auch (uint8_t*)0 == (void*)0 und damit ein Null-Pointer).
An Adrese 0 kann durchaus etwas Sinnvolles stehen. Z.B. Resetvektoren oder Register. Aber für den normalen Nutzer eher nicht. Darum hat man diese Adresse genommen NULL bedeutet lediglich "ungültige Adresse" (einen Wert musste man halt nehmen) Wenn man Zugriffsrechte auf die Adresse 0 hat, kann man auch einen NULL-Pointer dereferenzieren.
Dirk B. schrieb: > Wenn man Zugriffsrechte auf die Adresse 0 hat, kann man auch einen > NULL-Pointer dereferenzieren. Und hat damit undefined behaviour.
mh schrieb: > Dirk B. schrieb: >> Wenn man Zugriffsrechte auf die Adresse 0 hat, kann man auch einen >> NULL-Pointer dereferenzieren. > > Und hat damit undefined behaviour. Bei einigermassen aktuellem gcc wird das beispielsweise mit einem abort() bestraft, wenn man beim Compilieren nicht -no-delete-null-pointer-checks mitgibt.
Das ist gennauso wie der cast per Union im Standard UB, in der Praxis funktionierts halt trotzdem. Oliver
mh schrieb: > Dirk B. schrieb: >> Wenn man Zugriffsrechte auf die Adresse 0 hat, kann man auch einen >> NULL-Pointer dereferenzieren. > > Und hat damit undefined behaviour. Was soll an einem Zugriff auf das erste Byte/Wort/DWord/... UB sein. Es kann sein daß da nichts sinnvolle gemapped ist, aber sonst ... Bei STM32F103 (da hab ich gerade die Doku zur Hand) findet man dort den Anfang des Flashs. Oder ist UB schon, daß man den Inhalt des Flashs (fast) beliebig gestalten kann. Meine Intension war eigentlich, einem unerfahrenen TO mitzugeben, daß der Zugriffsfehler eines großen OS bei Benutzung des Nullptrs von eben diesem OS mit speziellen Tricks erzwungen wird und nichts mit mit der magischen Zahl Null zu tun hat. Was glaubst du passiert, wenn man auf einem AVR mit malloc() Speicher holt, keine Prüfung auf NULL als Resultat macht und den neu beschafften Speicherbereich beschreibt. Da kommt keine allgemeine Schutzverletzung, da sind die CPU-Register Müll.
Carl D. schrieb: > Was soll an einem Zugriff auf das erste Byte/Wort/DWord/... UB sein. Es ist UB einen Null-Pointer zu dereferenzieren. Carl D. schrieb: > Was glaubst du passiert, wenn man auf einem AVR mit malloc() Speicher > holt, keine Prüfung auf NULL als Resultat macht und den neu beschafften > Speicherbereich beschreibt. Da kommt keine allgemeine Schutzverletzung, > da sind die CPU-Register Müll. So manifestiert der Compiler auf einem AVR dieses spezielle UB.
mh schrieb: > Es ist UB einen Null-Pointer zu dereferenzieren. aus dem ISO-C Standard: 6.3.2.3 Pointers 3) An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. J.3.12 Implementation defined behavior The null pointer constant to which the macro NULL expands -> Es ist nirgentwo definiert dass in einem NULL pointer auch "0" drin stehen muss als Addresse. Es ist also denkbar, dass ein Pointer an RAM-Addresse 0 zeigt und trotzdem nicht als NULL-Pointer zählt. damit wäre *(int *)0 erlaubt.
Hier wird auch mal kurz das Ding mit dem dereferenzieren von NULL-Pointern angesprochen: https://youtu.be/yG1OZ69H_-o Ziemlich zu Anfang, bei ca. 5:30
:
Bearbeitet durch User
Markus F. schrieb: > Bei einigermassen aktuellem gcc wird das beispielsweise mit einem > abort() bestraft, wenn man beim Compilieren nicht > -no-delete-null-pointer-checks mitgibt. avr-gcc verwendet -fno-delete-null-pointer-checks, und zwar hart: http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr.c?view=markup&pathrev=254003#l725 IUnknown schrieb: > -> Es ist nirgentwo definiert dass in einem NULL pointer auch "0" drin > stehen muss als Addresse. Es ist also denkbar, dass ein Pointer an > RAM-Addresse 0 zeigt und trotzdem nicht als NULL-Pointer zählt. Soweit ACK. > damit wäre *(int *)0 erlaubt. Seh ich nicht so, denn (int*) 0 ist immer noch als Null-Pointer festgelegt (auch wenn die interne Darstellung ungleich 0x0 ist). An eine gültige Adresse, die physisch 0x0 enthält, käme man dann nur dadurch, dass man die Adresse eines Objekts nimmt, dass an 0x0 beginnt. Anm: Bei avr-gcc gibt es keine Objekte, sie sinnvoll an Adresse 0x0 liegen, zumindest wenn man reale Hardware voraussetzt und nicht irgendeinen AVR-Simulator. Von daher ist 0x0 als Wert für (void*)0 naheliegend und auch so implementiert.
Johann L. schrieb: > Seh ich nicht so, denn (int*) 0 ist immer noch als Null-Pointer > festgelegt (auch wenn die interne Darstellung ungleich 0x0 ist). Richtig. Eher so: *((int *)4 - 1)
Johann L. schrieb: > Seh ich nicht so, denn (int*) 0 ist immer noch als Null-Pointer > festgelegt (auch wenn die interne Darstellung ungleich 0x0 ist). Sagt der Standard nicht nur, dass (void*)0 die "null pointer constant" ist und alle anderen "null pointer" beim Vergleich mit der "null pointer constant" true ergeben müssen? In dem Fall wäre es möglich, dass (int*)0 kein null pointer ist, auch wenn es ziemlich schwachsinnig wäre es umzusetzen.
futz schrieb: > Ich übergebe einer Funktion einen Pointer auf eine Variable (in C). Wenn > diese Variable noch keinen gültigen Wert erhalten hat (z.B. Variable > enthält letzten Messwert, es wurde aber noch keine Messung > durchgeführt), würde ich das gerne meiner Funktion mitteilen. So weit, so gut. > Also, so dachte ich mir, übergebe ich einen NULL-Pointer Aber hier wird es Käse. Warum rufst du die Funktion überhaupt auf, wenn du keine gültigen Daten zu übergeben hast? Warum übergibst du überhaupt einen Pointer und nicht den Wert? Einen Pointer übergibt man eigentlich nur in 2 Fällen: 1. die Variable ist in Wirklichkeit eine struct von einiger Größe und es wäre ineffizient, erst eine Kopie davon anzulegen. Dann übergibt man aber einen Pointer auf const. 2. man will den Wert der Variablen (das worauf der Pointer zeigt) innerhalb der Funktion ändern. Dann darf man aber keinen Nullpointer übergeben, denn die Funktion würde beim Versuch des Schreibens das Programm zu Absturz bringen. Wie man es dreht und wendet, es ist unsinnig. Sauber könntest du das auf verschiedene Arten lösen: a) du initialisierst die Variable mit einem unmöglichen Wert. Das nennt sich inband signaling und ist in C weit verbreitet. Z.B. Funktionen, die normal nur positive Werte liefern können, im Fehlerfall aber z.B. -1. b) du spendierst der Funktion einen weiteren Parameter, für die Gültigkeit des Meßwerts. Das heißt dann out-of-band signaling und gilt allgemein als sauberer.
Ich schätze, den Wert 0 hat man benutzt, weil den etliche CPU's schnell erkennen können (Stichwort Zero-Flag). Und natürlich, weil diejenigen, die das festgelegt haben Architekturen gewöhnt waren, bei denen an Adresse 0 nichts vom C-Programm liegen konnte. In der Tat kann es vorkommen, dass 0 eine gültige Adresse von Daten ist. Dann muss man halt ein wenig tricksen, damit nichts, auf was ein Zeiger zeigen soll, dort zu liegen kommt. Und bei Architekturen mit mehreren Adressbereichen, sollte ein Pointer IMHO auch immer eine Info beinhalten, welcher Adressbereich gemeint ist. Wenn man versucht, sich das zu ersparen, kommt man auf ganz seltsame Konstrukte, wie z.B. Attribut Progmem. Wobei ich sagen würde, dass der 8032 über 4 Adressbereiche (Verschiedenes unter der selben Nummer) verfügt.
Vorsicht, Falle! Bei den AVRs hatte ich mehr als einmal den Fehler gemacht, einen Nullpointer abzufangen ohne daran zu denken, dass an Adresse 0 im EEPROM gültige Daten liegen. Bei den meisten Systemen liegt aber an Adresse 0 etwas, auf das eine Applikation nicht zugreifen muss. Daher diese Konvention, insbesondere weil alle (mir bekannten) CPUs das erkennen einer Null unterstützen.
:
Bearbeitet durch User
Detlev T. schrieb: > Vorsicht, Falle! Bei den AVRs hatte ich mehr als einmal den Fehler > gemacht, einen Nullpointer abzufangen ohne daran zu denken, dass an > Adresse 0 im EEPROM gültige Daten liegen. Aus dem Mega48/88/168/328 DB:
1 | The lower 768/1280/1280/2303 data memory locations address both the Register File, the I/O memory, Extended I/O memory, and the internal data SRAM. The first 32 locations address the Register File, the next 64 location the standard I/O memory, then 160 locations of Extended I/O memory, and the next 512/1024/1024/2048 locations address the internal data SRAM |
Mit *(uint8_t*)(0)=42; schreibt man 42 ins R0. Das sind gültige Daten, aber nur selten ist sowas beabsichtigt und danach verhält sich das Programm meist undefined. Anwendungen außer kryptifizierung eines Programms (unter Verschwendung der wertvollen Pointer-Register): keine. > > Bei den meisten Systemen liegt aber an Adresse 0 etwas, auf das eine > Applikation nicht zugreifen muss. Daher diese Konvention, insbesondere > weil alle (mir bekannten) CPUs das erkennen einer Null unterstützen. "Nicht muß" ist deutlich schwächer als das "nicht kann" der Systeme mit MMU. Und vereinzelt (aVR) hat ein Schreibzugrif auf nullptr üble Nebenwirkungen.
@Carl Drexler RAM != EEPROM Beim AVR haben Flash, RAM und EEPROM getrennte Adressbereiche, alle fangen mit Adresse 0 an.
Detlev T. schrieb: > @Carl Drexler > > RAM != EEPROM > > Beim AVR haben Flash, RAM und EEPROM getrennte Adressbereiche, alle > fangen mit Adresse 0 an. Echt jetzt?
Johann L. schrieb: >> damit wäre *(int *)0 erlaubt. > > Seh ich nicht so, denn (int*) 0 ist immer noch als Null-Pointer > festgelegt (auch wenn die interne Darstellung ungleich 0x0 ist). Richtig. > An eine gültige Adresse, die physisch 0x0 enthält, käme man dann nur > dadurch, dass man die Adresse eines Objekts nimmt, dass an 0x0 beginnt. Nein. Man käme dahin z.B. mit:
1 | int x = 0; |
2 | void* p = (void*)x; |
Denn nur ein konstanter Integer-Ausdruck mit dem Wert 0 führt zu einem Nullzeiger. x ist hier aber kein konstanter Ausdruck. Ma W. schrieb: > Johann L. schrieb: >> Seh ich nicht so, denn (int*) 0 ist immer noch als Null-Pointer >> festgelegt (auch wenn die interne Darstellung ungleich 0x0 ist). > > Richtig. > Eher so: > > *((int *)4 - 1) Ist allerdings formal auch undefiniertes Verhalten, da man Zeigerarithmetik nur innerhalb eines tatsächlich existierenden Arrays durchführen darf. Aber wenn man direkt auf eine vorgegebene Adresse zugreifen will, landet man da früher oder später eh.
:
Bearbeitet durch User
Johann L. schrieb: > avr-gcc verwendet -fno-delete-null-pointer-checks, und zwar hart: > > http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr.c?view=markup&pathrev=254003#l725 Was aber nichts am Standard ändert. NULL ist auf dem AVR trotzdem 0, und die Dereferenzierung funktioniert halt einfach. Das könnte man zwar auch als eine Variante von UB ansehen, ist es aber nicht. Oliver
Beitrag #5224894 wurde vom Autor gelöscht.
Oliver S. schrieb: > Das könnte man zwar auch als eine Variante von UB ansehen, ist es aber > nicht. Doch, selbstverständlich ist es das. Oder willst du sagen, C verbietet dieses Verhalten?
:
Bearbeitet durch User
futz schrieb: > Ich frage mich nun, ob (bzw. warum) es ausgeschlossen ist, dass sich > eine Variable tatsächlich an der Adresse 0 befindet. > Für einen kleinen Hinweis wäre ich dankbar. kleiner Hinweis: Es ist GARNICHTS ausgeschlossen. Einen Zeiger auf 0 als ungültig anzusehen, ist ganz einfach eine Konvention und sonst nichts. Selbstverständlich kann sich auf Adresse 0 auch irgend etwas befinden - und bei den allermeisten Systemen ist dort auch tatsächlich etwas. Bei einigen Fujitsu-Controllern befand sich dort der Schnellzugriffsbereich 0..255 auf eine Reihe von Registern. W.S.
W.S. schrieb: > futz schrieb: >> Ich frage mich nun, ob (bzw. warum) es ausgeschlossen ist, dass sich >> eine Variable tatsächlich an der Adresse 0 befindet. >> Für einen kleinen Hinweis wäre ich dankbar. > > kleiner Hinweis: > Es ist GARNICHTS ausgeschlossen. Einen Zeiger auf 0 als ungültig > anzusehen, ist ganz einfach eine Konvention und sonst nichts. Ist halt nur blöd, daß ein Nullpointer nicht zwangsläufig ein "Zeiger auf 0" sein muß. "Nullpointer" ist der Fachbegriff für "Pointer der auf nichts zeigt, der insbesondere nicht dereferenziert werden kann". Das ist ein abstraktes Konzept und hat mit dem Wert 0 nahezu nichts zu tun. Außer, daß man halt einen Weg vorsehen mußte, einen Nullpointer zu konstruieren. Und dazu hat man sich entschieden, den Cast der Konstante 0 zu einem Pointer zu verwenden. Und das ist hier die Konvention. Weder muß der "Wert" eines Nullpointers 0 sein, noch muß es dazu unmöglich sein, ein Objekt an der Speicheradresse 0 anzulegen. Für den C-Compiler sind Adressen und Pointer eben nicht das gleiche, sondern nur fast.
Axel S. schrieb: > Ist halt nur blöd, daß ein Nullpointer nicht zwangsläufig ein "Zeiger > auf 0" sein muß. Nö. Ein Nullpointer ist ein Pointer, der auf Aresse 0 zeigt und nix anderes. Deswegen heißt er ja auch so. Und der TO hat sich ausdrücklich darauf bezogen. Vielleicht verwechselst du das mit Pascal, dort heißt der ungültige Pointer "nil", abgekürzt von "nihil" was zu deutsch "nichts" heißt. Und nil ist dort ein Schlüsselwort, ganz im Gegensatz zu "NULL" bei C, was bloß eine Text-Ersetzung für 0 ist. W.S.
W.S. schrieb: > Axel S. schrieb: >> Ist halt nur blöd, daß ein Nullpointer nicht zwangsläufig ein "Zeiger >> auf 0" sein muß. > > Nö. > > Ein Nullpointer ist ein Pointer, der auf Aresse 0 zeigt und nix anderes. Das ist falsch Siehe: http://c-faq.com/null/null1.html http://c-faq.com/null/machnon0.html > ... "NULL" bei C, was bloß eine Text-Ersetzung für 0 ist. Und auch das ist falsch NULL ist ein C-Makro, das normalerweise zu ((void *)0) expandiert. Und das ist eben nicht der Wert 0.
W.S. schrieb: > Selbstverständlich kann sich auf Adresse 0 auch irgend etwas befinden > - und bei den allermeisten Systemen ist dort auch tatsächlich etwas. > W.S. Eine sehr gewagte Aussage. Auf Allen Windows NT basierten Systemen (also fapp allen Windows Maschinen) ist dort per Definition "nichts," weil das OS per-Prozess virtuelle Adressbereiche führt und die erste "Seite" jedes virtuellen Speichers (also genau dort wo Adresse 0 hereinfallen würde) niemals gültig gemappt ist. Ein Versuch, 0 innerhalb einer Task zu dereferenzieren führt also immer zu einem Page Fault.
Dave C. schrieb: > W.S. schrieb: >> Selbstverständlich kann sich auf Adresse 0 auch irgend etwas befinden >> - und bei den allermeisten Systemen ist dort auch tatsächlich etwas. >> W.S. > > Eine sehr gewagte Aussage. Vor allem komplett am Thema vorbei. Per Definition ist der Nullpointer ein Pointer, der verschieden von jedem Pointer auf irgendeine Variable oder Funktion ist. Das heißt, wenn auf der Zielarchitektur ein Objekt auf Adresse 0 liegen kann, dann kann der Nullpointer auf dieser Architektur nicht der Adresse 0 entsprechen. Das Konzept Pointer in C ist eben nicht das gleiche wie eine Adresse in Assembler. Es ist nur fast das gleiche. Die Existenz des Nullpointers ist da nur ein Punkt. Andere Abweichungen haben Pointer bei der Arithmetik, wo der Typ des referenzierten Objekt berücksichtigt wird.
Axel S. schrieb: > Das heißt, wenn auf der Zielarchitektur ein Objekt > auf Adresse 0 liegen kann, dann kann der Nullpointer auf dieser > Architektur nicht der Adresse 0 entsprechen. Und da sind wir dann wieder beim Unterschied zwischen Theorie und Praxis. Denn es gibt halt doch Zielarchitekturen, z.B. AVR, bei denen das genauso ist. Oliver
Oliver S. schrieb: > Axel S. schrieb: >> Das heißt, wenn auf der Zielarchitektur ein Objekt >> auf Adresse 0 liegen kann, dann kann der Nullpointer auf dieser >> Architektur nicht der Adresse 0 entsprechen. > > Und da sind wir dann wieder beim Unterschied zwischen Theorie und > Praxis. Denn es gibt halt doch Zielarchitekturen, z.B. AVR, bei denen > das genauso ist. Wenn das so ist, dann ist der Compiler potentiell nicht standardkonform. Potentiell deswegen, weil der Compiler das Problem immer noch dadurch entschärfen kann, daß er an Adresse 0 einfach kein Objekt anlegt, auch wenn er es im Prinzip könnte. Ich bin aber kein intimer Kenner des C-Standards bzw. dessen Auslegung.
Nee, das passt schon. Das SRam fängt beim AVR auch erst weiter oben an, auf Adresse 0 befindet sich das IO-gemappte Register R0. Damit kann der Compiler niemals eigene Objekte dorthin legen, allerdings ist trotzdem ein Zugriff auf die Adresse möglich und auch im Einzelfall erforderlich. Oliver
Oliver S. schrieb: > ... > allerdings ist trotzdem ein Zugriff auf die Adresse möglich und auch im > Einzelfall erforderlich. Kannst du auch zeigen wie man das in C macht, ohne dabei undefined behaviour auszunutzen?
1 | uint8_t* ptr = 0; |
2 | *ptr = 42; |
Ist UB in C.
Axel S. schrieb: > Das heißt, wenn auf der Zielarchitektur ein Objekt > auf Adresse 0 liegen kann, dann kann der Nullpointer auf dieser > Architektur nicht der Adresse 0 entsprechen. Ein null pointer zeigt auf addresse 0, egal welche Architektur. Bei Linux gabs deswegen mal einen gefärlichen Bug: https://lwn.net/Articles/342330/
mh schrieb: > Ist UB in C Funktioniert aber trotzdem. Theorie und Praxis... Wie Johann weiter oben schrieb, ist der Compiler mit -fno-delete-null-pointer-checks konfiguriert. Damit vermeidet der zumindest alle Optimierungen, die darauf basieren, daß ein Zugriff auf die Addresse 0 nicht erlaubt ist. Oliver
:
Bearbeitet durch User
Vielleicht dazu noch ein Beispiel aus der Praxis. Im embOS werden alle Task Control Blöcke als verkettete Liste behandelt. Der letzte TCB zeigt auf NULL. Der Renesas RX Core hat RAM ab Adresse 0. Es wäre also blöd, wenn ein TCB am Anfang des RAMs liegen würde. In solchen Fällen definieren wir im Linkerfile die RAM Startadresse als 0x04. Damit verschenkt man zwar 4 Bytes RAM aber hat das Problem einfach umgangen. Das gleiche Prinzip wurde weiter oben auch schon beschrieben.
W.S. schrieb: > Ein Nullpointer ist ein Pointer, der auf Aresse 0 zeigt und nix anderes. > Deswegen heißt er ja auch so. > Und der TO hat sich ausdrücklich darauf bezogen. Dadurch wird es aber nicht automatisch richtig. > Vielleicht verwechselst du das mit Pascal, dort heißt der ungültige > Pointer "nil", abgekürzt von "nihil" was zu deutsch "nichts" heißt. Und du verwechselst offenbar das englische "null" mit der deutschen Null. "null" kann auch soviel wie "nichts" oder "ungültig" heißen. Daniel A. schrieb: > Axel S. schrieb: >> Das heißt, wenn auf der Zielarchitektur ein Objekt >> auf Adresse 0 liegen kann, dann kann der Nullpointer auf dieser >> Architektur nicht der Adresse 0 entsprechen. > > Ein null pointer zeigt auf addresse 0, egal welche Architektur. Das könnt ihr noch so oft behaupten, es bleibt falsch! Axel Schwenke hat das oben sehr gut erklärt. Es gibt in ISO C keine Stelle, die so etwas fordert. In der "rationale" zu C99 ist das aber nochmal explizit erklärt, da sich dieser Umstand auch auf implizite Initialisierungen auswirkt. So heißt es dort in §6.7.8 "Initialization": An implementation might conceivably have codes for floating zero and/or null pointer other than all bits zero. In such a case, the implementation must fill out an incomplete initializer with the various appropriate representations of zero; it may not just fill the area with zero bytes. As far as the committee knows, all machines treat all bits zero as a representation of floating-point zero. But, all bits zero might not be the canonical representation of zero. ( http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf )
:
Bearbeitet durch User
Rolf M. schrieb: > Daniel A. schrieb: >> Axel S. schrieb: >>> Das heißt, wenn auf der Zielarchitektur ein Objekt >>> auf Adresse 0 liegen kann, dann kann der Nullpointer auf dieser >>> Architektur nicht der Adresse 0 entsprechen. >> >> Ein null pointer zeigt auf addresse 0, egal welche Architektur. > > Das könnt ihr noch so oft behaupten, es bleibt falsch! Axel Schwenke > hat das oben sehr gut erklärt. Es gibt in ISO C keine Stelle, die so > etwas fordert. In der "rationale" zu C99 ist das aber nochmal explizit > erklärt, da sich dieser Umstand auch auf implizite Initialisierungen > auswirkt. Es existieren aber keine Implementierungen, die soetwas tun würden. Es wird auch niemals welche geben, weil dann sämtlicher Code, der davon ausgeht nichtmehr funktionieren würde. Das würde sämtliche Programme betreffen, die memset oder calloc verwenden, um Arrays oder Strukturen auszunullen, die Pointer beinhalten, also so ziemlich jedes Programm. Deshalb ist es auch vollkommen egal, ob der Standard das erlauben würde, es gibt einfach keinen Compiler bauer, der dumm genug wäre, das zu tun, und deshalb zeigt ein null pointer auch weiterhin immer auf 0, bei jeder Implementierung. Ernsthaft, was zum teufel hat das Standard komitee sich bei dem Blödsinn nur gedacht? Axel S. schrieb: > 2. man will den Wert der Variablen (das worauf der Pointer zeigt) > innerhalb der Funktion ändern. Dann darf man aber keinen Nullpointer > übergeben, denn die Funktion würde beim Versuch des Schreibens das > Programm zu Absturz bringen. Man kann auch einfach in der Funktion vorher prüfen, ob der Pointer 0 ist.
Daniel A. schrieb: > Es existieren aber keine Implementierungen, die soetwas tun würden. Es > wird auch niemals welche geben, ... Ich bin ja erstaunt, dass du alle Implementierungen dieser Welt kennst, aber vollkommen beeindruckt, dass du auch alle Implementierungen kennst, die es jemals geben wird. Meine Hochachtung. Daniel A. schrieb: > Ernsthaft, was zum teufel hat das Standard komitee sich > bei dem Blödsinn nur gedacht? Sie haben auf eine Scheuklappe verzichtet und damit Implementationen ermöglicht, für die es möglicherweise vorteilhafter ist, das Problem anders anzugehen. Es gibt ziemlich verkorkste Architekturen auf diesem Planeten, die trotzdem in Standard-C programmiert werden können und nicht zwingend auf esoterische Spezialsprachen angewiesen sind. Das ist ein massiver Vorteil von C gegenüber anderen Sprachen und Umgebungen, und dem trägt der Standard Rechnung.
Daniel A. schrieb: > Es existieren aber keine Implementierungen, die soetwas tun würden. Falsch, siehe http://c-faq.com/null/machexamp.html Und ja, ich habe gesehen, dass es bei einem der Systeme später geändert wurde, weil's zuviel kaputten Code gibt, der falsche Annahmen trifft.
Daniel A. schrieb: > Es existieren aber keine Implementierungen, die soetwas tun würden. Das stimmt nicht. > Es wird auch niemals welche geben Das kannst du gar nicht wissen. > weil dann sämtlicher Code, der davon > ausgeht nichtmehr funktionieren würde. Die Existenz von kaputtem Code belegt gar nichts. Außer natürlich die Existenz von unfähigen Programmierern. Allerdings haben wir hier im Forum ja auch einen Bildungsauftrag. Angesichts dessen kann man gar nicht oft genug wiederholen, was einen Nullpointer auszeichnet und daß es nur einen korrekten Weg gibt, einen Nullpointer zu erzeugen, nämlich indem man das Literal 0 zu einem Pointer casted (was der Compiler aber bspw. bei Zuweisungen automatisch macht).
:
Bearbeitet durch User
Es ist immer möglich einnen null Pointer als 0 zu implementieren, es wäre höchstens manchmal etwas weniger effizient. Ich hätte nie gedacht, dass es tatsächlich c compiler implementationen gibt, die dies nicht tun. Ich verliere langsam jegliche Hoffnung für die Menschheit... Gibt es wenigstens einen Weg um zur compile time zu prüfen, ob ein null Pointer 0 ist? Ich denke an irgendwas in die richtung:
1 | static_assert( ((union {void* p; uintptr_t i;}){0}).i != 0, "NULL isn't 0"); |
Aber das wäre UB, gibt es da irgend eine bessere Methode?
Daniel A. schrieb: > Gibt es wenigstens einen Weg um zur compile time zu prüfen, ob ein null > Pointer 0 ist? Sicher. Initialisiere einen Pointer mit memset() und vergleiche ihn dann mit einem richtigen Nullpointer.
1 | char *x; |
2 | memset(&x, 0, sizeof(x)); |
3 | if (x != (char *)0) { |
4 | printf("Nullpointer != 0\n"); |
5 | }
|
:
Bearbeitet durch User
Axel S. schrieb: > Daniel A. schrieb: >> Gibt es wenigstens einen Weg um zur compile time zu prüfen, ob ein null >> Pointer 0 ist? > > Sicher. Initialisiere einen Pointer mit memset() und vergleiche ihn dann > mit einem richtigen Nullpointer. Das wäre aber zur Runtime, nicht zur compile time. Soetwas will ich merken, befor ich das Program starte.
Daniel A. schrieb: > Es ist immer möglich einnen null Pointer als 0 zu implementieren, es > wäre höchstens manchmal etwas weniger effizient. Es gibt Architekturen, deren Adressraum signed ist und wo "Adresse 0x0000" genau in der Mitte des Adressraums ist, da wäre die Festlegung ziemlich b'schissen. Der C-Standard ist darauf ausgelegt, auf jeder noch so verkorksten Architektur einigermaßen gebrauchbar implementierbar zu sein. Die abstrakte Maschine ist deswegen wesentlich abstrakter als bei anderen Sprachen. Daniel A. schrieb: > Gibt es wenigstens einen Weg um zur compile time zu prüfen, ob ein null > Pointer 0 ist? Warum solltest du das tun wollen? Du weißt, auf welchen Architekturen und mit welchen Compilern dein Programm läuft. Und wenn jemand einen Transputer-Compiler auspackt, dann ist der Port sein Problem, solange du nicht explizit "tut auch da" ranschreibst.
S. R. schrieb: > Daniel A. schrieb: >> Es ist immer möglich einnen null Pointer als 0 zu implementieren, es >> wäre höchstens manchmal etwas weniger effizient. > > Es gibt Architekturen, deren Adressraum signed ist und wo "Adresse > 0x0000" genau in der Mitte des Adressraums ist, da wäre die Festlegung > ziemlich b'schissen. Ich sehe hier kein grosses Problem. Man muss nur darauf achten, dass dynamische Allocationen nicht exact an der Addresse anfangen, und bei der ABI des Compilers die Dereferenzierung eines 0 pointers erlauben, und dann sollte es eigentlich keine grösseren Probleme geben. > Daniel A. schrieb: >> Gibt es wenigstens einen Weg um zur compile time zu prüfen, ob ein null >> Pointer 0 ist? > > Warum solltest du das tun wollen? > > Du weißt, auf welchen Architekturen und mit welchen Compilern dein > Programm läuft. Und wenn jemand einen Transputer-Compiler auspackt, dann > ist der Port sein Problem, solange du nicht explizit "tut auch da" > ranschreibst. Ich schreibe meine Programme immer so, dass diese auf möglichst vielen Platformen laufen. Wenn ich doch mal eine Annahme treffe kontrolliere ich diese mit einem static_assert. Es spielt für mich keine rolle, wer den Code womöglich später portiert oder anderweitig weiterverwendet. Aber debugging kann wirklich lästig sein, weshalb ich dem Programmierer lieber schon beim Compilieren wissen lassen will, wenn es ein Problem gibt und was das Problem ist.
Daniel A. schrieb: > Ich sehe hier kein grosses Problem. Man muss nur darauf achten, dass > dynamische Allocationen nicht exact an der Addresse anfangen, und bei > der ABI des Compilers die Dereferenzierung eines 0 pointers erlauben, > und dann sollte es eigentlich keine grösseren Probleme geben. Nur ungefähr die halbe c Standard Lib ist nicht mehr nutzbar, da sie NULL irgendwo in den Vor- oder Nachbedingungen nutzen.
Daniel A. schrieb: >> Es gibt Architekturen, deren Adressraum signed ist und wo "Adresse >> 0x0000" genau in der Mitte des Adressraums ist, da wäre die Festlegung >> ziemlich b'schissen. > > Ich sehe hier kein grosses Problem. [...] Für den Assemblerprogrammierer kein Problem (und unnötig), für einen Compiler ist deine Forderung real äquivalent zu "die RAM-Zelle an Adresse 0 wird nicht benutzt". Damit teilst du den Adressraum mittig in zwei Teile, was deutlich unangenehmer ist als ein Nullpointer mit gesetzten Bits. Daniel A. schrieb: > Ich schreibe meine Programme immer so, dass diese auf möglichst vielen > Platformen laufen. Das heißt, du benutzt keinerlei Bibliotheken (außer der C-Standardbibliothek) und du benutzt keine Betriebssysteme o.ä.? Wenn du esoterische Plattformen (seltsame DSPs, komische verteilte Systeme der 80er, Mikrocontroller mit getrennten Adressräumen) mit deinem Code genauso unterstützen willst wie PCs und Smartphones, dann machst du meiner Meinung nach irgendetwas grundsätzlich falsch. Irgendwo gibt es sinnvolle Grenzen der Portabilität.
Daniel A. schrieb: >>> Gibt es wenigstens einen Weg um zur compile time zu prüfen, ob ein null >>> Pointer 0 ist? >> >> Warum solltest du das tun wollen? > > Ich schreibe meine Programme immer so, dass diese auf möglichst vielen > Platformen laufen. Dann ist das doch ganz unnötig. Verwende einfach den standardkonformen Weg, einen Nullpointer zu initialisieren. Dann ist es 100%ig portabel.
S. R. schrieb: > Daniel A. schrieb: >> Ich schreibe meine Programme immer so, dass diese auf möglichst vielen >> Platformen laufen. > > Das heißt, du benutzt keinerlei Bibliotheken (außer der > C-Standardbibliothek) und du benutzt keine Betriebssysteme o.ä.? Es kommt darauf an, was ich Programmiere. Bei PC Programmen setze ich mindestens das vorhandensein eines OS und der meisten POSIX funktionen voraus. Fremde Libraries versuche ich möglichst selten zu verwenden, nur wenn es etwas aufwendigeres wie ein Parser oder etwas weit verbreitetes oder etwas dessen Code überschaubar ist ist verwende ich libraries. Wenn ich ein uC Programm erstelle halte ich es modular genug, damit ich es auch auf dem PC nativ laufen und debuggen lassen kann. In dem fall verwende ich keine fremden libraries. Aber bei so exotischen dingen wie 7bit Systemen ziehe ich eine grenze, das ist den Aufwand einfach nicht wert. Axel S. schrieb: >> Ich schreibe meine Programme immer so, dass diese auf möglichst vielen >> Platformen laufen. > > Dann ist das doch ganz unnötig. Verwende einfach den standardkonformen > Weg, einen Nullpointer zu initialisieren. Dann ist es 100%ig portabel. Dann müsste ich bei sämtlichen meiner Programme nochmal die Sourcen durchgehen und alle Stellen finden, an denen ich diese Annahme getroffen habe, das wäre ziemlich aufwendig. Die Programme müssen ja nicht auf allen Platformen laufen, nur auf möglichst vielen. Bei meinen PC Programmen bin ich mir nicht sicher ob die üblichen Betriebssysteme überhaupt auf Systemen funktionieren würden dessen Kompiler solch exotische null pointer haben, deshalb erscheint mir dort ein static_assert sinvoller als alle sourcen anzupassen.
Daniel A. schrieb: >> Es gibt Architekturen, deren Adressraum signed ist und wo "Adresse >> 0x0000" genau in der Mitte des Adressraums ist, da wäre die Festlegung >> ziemlich b'schissen. > > Ich sehe hier kein grosses Problem. Man muss nur darauf achten, dass > dynamische Allocationen nicht exact an der Addresse anfangen, Sie dürfen nicht nur nicht exakt dort anfangen, sondern diese Adresse muss komplett außerhalb des allokierten Blocks liegen. Dieser muss also entweder vor dieser Adresse aufhören oder danach anfangen. Es ist vor allem bei der Allokation von großen Objekten ziemlich blöd, wenn mitten im Adressraum ein Byte ist, das nicht genutzt werden darf. > und bei der ABI des Compilers die Dereferenzierung eines 0 pointers > erlauben, und dann sollte es eigentlich keine grösseren Probleme geben. Dann müsste das ABI aber auch die C-Regel brechen, dass ein Vergleich der Adresse eines gültigen Objekts mit einem NULL-Zeiger niemals Gleichheit ergeben darf. Daniel A. schrieb: > Aber bei so exotischen dingen wie > 7bit Systemen ziehe ich eine grenze, das ist den Aufwand einfach nicht > wert. C garantiert dir, dass char mindestens 8 Bit breit ist. Auf einem 7-Bit-System würde ein Compiler-Hersteller char dann wohl 14 Bit breit machen. Wäre aber mal interessant, wieviel Code auf so einem System noch funktioniert.
Daniel A. schrieb: > Bei PC Programmen setze ich mindestens das vorhandensein > eines OS und der meisten POSIX funktionen voraus. Dort ist der Wert eines Nullpointers immer "kein Bit gesetzt" und CHAR_BITS ist 8. Kannst du dich drauf verlassen. Daniel A. schrieb: > Aber bei so exotischen dingen wie 7bit Systemen ziehe ich > eine grenze, das ist den Aufwand einfach nicht wert. Dann darfst du einfach annehmen, dass der Wert eines Nullpointers "kein Bit gesetzt" ist. Abweichende Systeme sind Exoten. Daniel A. schrieb: > Die Programme müssen ja nicht auf > allen Platformen laufen, nur auf möglichst vielen. Dann darfst du einfach annehmen, dass der Wert eines Nullpointers "kein Bit gesetzt" ist. Abweichende Systeme sind extrem selten und eher historisch. Falls du wirklich einmal in die Verlegenheit kommen solltest, deinen Code auf einer extrem ungewöhnlichen Plattform einsetzen zu wollen, kannst du ihn ja gezielt darauf geradeziehen. Ungewöhnliche Nullpointer sind dann aber vermutlich dein geringstes Problem. Daniel A. schrieb: > Bei meinen PC Programmen bin ich mir nicht sicher ob die üblichen > Betriebssysteme überhaupt auf Systemen funktionieren würden dessen > Kompiler solch exotische null pointer haben, Es existieren keine solchen Compiler und für heute übliche Architekturen wird es wahrscheinlich auch nie solche Compiler geben. Es existiert schlicht keine Notwendigkeit dafür (außerdem gibt es MMUs).
Dirk B. schrieb: > An Adrese 0 kann durchaus etwas Sinnvolles stehen. > Z.B. Resetvektoren oder Register. > > Aber für den normalen Nutzer eher nicht. Darum hat man > diese Adresse genommen > NULL bedeutet lediglich "ungültige Adresse" > (einen Wert musste man halt nehmen) Muss man nicht. Man hätte Referenzen auch als Paare [Startadr; (Endadr+1)] definieren können; auf diese Art könnte man den gesamten Speicher adressieren und hätte gleichzeitig die Möglichkeit zur Bereichsprüfung. NIL-Referenzen wären dann einfach solche mit "Startadr >= Endadr". Ich dachte in meiner Jugend, bei Programmiersprachen ginge es primär um Klarheit im Ausdruck, Kompaktheit, Lesbarkeit, Vermeidung von Fehlern. Die völlig unsinnigen Diskussionen um Wahrheitswerte und NULL-Pointer zeigen mir aber zweierlei: 1. S/M ist in der Mitte der Gesellschaft angekommen. 2. Das Erlernen der Programmiersprache "C" ist ein Initiationsritual, das einen in die Gemeinschaft der "richtigen" Programmierer aufnimmt.
Daniel A. schrieb: > Axel S. schrieb: >> Daniel A. schrieb: >>> Gibt es wenigstens einen Weg um zur compile time zu prüfen, ob ein null >>> Pointer 0 ist? >> >> Sicher. Initialisiere einen Pointer mit memset() und vergleiche ihn dann >> mit einem richtigen Nullpointer. > > Das wäre aber zur Runtime, nicht zur compile time. Soetwas will ich > merken, befor ich das Program starte. Das willst du am besten bereits wissen, bevor du die erste Zeile Code schreibst (wenn der Code denn so un-portierbar ist, dass er eine bestimmte Binärdarstellung von NULL erwartet). --> ABI lesen.
Rolf M. schrieb: > C garantiert dir, dass char mindestens 8 Bit breit ist. Auf einem > 7-Bit-System würde ein Compiler-Hersteller char dann wohl 14 Bit breit > machen. Wäre aber mal interessant, wieviel Code auf so einem System noch > funktioniert. Seit C99 immer weniger. Denn wenn viele meinen uint8_t wäre super, fallen sie dann auf die Schnauze. uint_least8_t oder sogar uint_fast8_t wären öfter angebracht.
Dirk B. schrieb: > Seit C99 immer weniger. > Denn wenn viele meinen uint8_t wäre super, fallen sie dann auf die > Schnauze. Wenn das System keinen 8 Bit Datentyp bietet, darf uint8_t gar nirgends definiert sein und damit kompiliert das gar nicht erst. Dann ist es zumindest direkt klar dass der Code nicht läuft ohne dass es zur Laufzeit komische Fehler gibt.
Possetitjel schrieb:
[merkwürdiges]
Das Hauptproblem liegt IMHO nicht in den Eigenheiten von C, sondern
darin, daß alle Welt C für eine geeignete Sprache zur Anwendungs-
programmierung hält. Dafür war C aber nie gedacht und ist folgerichtig
auch nicht sonderlich geeignet. Die Abwesenheit eines String-Datentyps
genauso wie nackte Pointer oder fehlende Bereichsprüfung bei z.B.
Array-Zugriffen belegen deutlich, daß bei C der Fokus auf Maschinennähe
und Performanz liegt. Die beste Beschreibung von C ist IMNSHO "portabler
Assembler".
Axel S. schrieb: > Das Hauptproblem liegt IMHO nicht in den Eigenheiten von C, sondern > darin, daß alle Welt C für eine geeignete Sprache zur Anwendungs- > programmierung hält. Ist das so? Wo kommt denn heute noch C bei Anwendungsentwicklung vor? > Dafür war C aber nie gedacht und ist folgerichtig > auch nicht sonderlich geeignet. Die Abwesenheit eines String-Datentyps > genauso wie nackte Pointer oder fehlende Bereichsprüfung bei z.B. > Array-Zugriffen belegen deutlich, daß bei C der Fokus auf Maschinennähe > und Performanz liegt. Die beste Beschreibung von C ist IMNSHO "portabler > Assembler". Darum ist es ja auch für Embedded Zeug so gut geeignet und wird nicht umsonst hier extrem oft verwendet.
Daniel A. schrieb: > Axel S. schrieb: >> Dann ist das doch ganz unnötig. Verwende einfach den standardkonformen >> Weg, einen Nullpointer zu initialisieren. Dann ist es 100%ig portabel. > > Dann müsste ich bei sämtlichen meiner Programme nochmal die Sourcen > durchgehen und alle Stellen finden, an denen ich diese Annahme getroffen > habe, das wäre ziemlich aufwendig. Das mußt du nicht. Verbuche das einfach als Jugendsünde und schreib deine zukünftige Software so, daß sie sich an standardkonformem Verhalten des Compilers orientiert und nicht auf implementation defined behavior setzen muß. Es gibt gute Gründe, hier und da ein bestimmtes IDB auszunutzen. Aber man muß sich halt im klaren sein, daß der Code dann nicht mehr portabel ist. Allerdings würde ich gerade Nullpointer nicht in diese Kategorie sortieren. Zumindest so lange man nicht mit inline Assembler hantiert. Ein portabler Nullpointer-Test in Assembler wird sicher unerfreulich.
Possetitjel schrieb: > Man hätte Referenzen auch als Paare [Startadr; (Endadr+1)] > definieren können Hätte man, wenn man extra langsame Systeme als Ergebnis gewollt hätte. Was man Dir in Deiner Jugend nicht erzählt hat: Performance zählt auch.
Axel S. schrieb: > Possetitjel schrieb: > [merkwürdiges] Ich hätte davon nicht anfangen sollen; konnte mich halt nur nicht beherrschen. Ich gelobe Besserung. > Das Hauptproblem liegt IMHO nicht in den Eigenheiten > von C, sondern darin, daß alle Welt C für eine geeignete > Sprache zur Anwendungsprogrammierung hält. Dieses "Missverständnis" wird aber dadurch aktiv gefördert, dass im Vorwort der mir vorliegenden Ausgabe des K&R drei Mal betont wird, C eigne sich "für einen breiten Anwendungsbereich". Genau betrachtet ist das gelogen -- C eignet sich NUR für maschinennahes Zeug, das portabel sein soll. Das sollte man -- wenigstens heutzutage -- auch so verkaufen. (Dass K&R vor 50 Jahren anderer Meinung waren, laste ich ihnen gar nicht an. Wir wissen es heute aber besser.) > Die beste Beschreibung von C ist IMNSHO "portabler > Assembler". Ja, sicher. - Das ist aber gar nicht mein Punkt: C ignoriert den Unterschied zwischen der Bedeutung eines Datenelementes einerseits und seiner Codierung andererseits. Wie krank ist denn eine Sprache, die zwar boolesche Ausdrücke auswerten kann, aber keinen eigenen Datentyp hat, um die Ergebnisse zu speichern?!
Possetitjel schrieb: > Wie krank ist denn eine Sprache, die zwar boolesche Ausdrücke > auswerten kann, aber keinen eigenen Datentyp hat, um die > Ergebnisse zu speichern?! Das folgt einfach der üblichen Implementierung des Z (Zero) Flags in der ALU. Z gesetzt = false, sonst true. Fertig. Wie gesagt: Effizienz zählt.
Nop schrieb: > Was man Dir in Deiner Jugend nicht erzählt hat: Vielleicht beschränkst Du Deine Urteile zukünftig auf Deine eigene Jugend; da liegst Du hoffentlich weniger oft daneben. > Performance zählt auch. Das hat man mir leider ein paar Mal zu oft erzählt. Überzeugendster Ausdruck dieser Strömung sind die Toten in der Silvesternacht 1999 in Berlin. Inzwischen weiss man: Verfrühte Mikrooptimierung ist die Wurzel alles Bösen.
Axel S. schrieb: > Possetitjel schrieb: >> Wie krank ist denn eine Sprache, die zwar boolesche >> Ausdrücke auswerten kann, aber keinen eigenen Datentyp >> hat, um die Ergebnisse zu speichern?! > > Das folgt einfach der üblichen Implementierung des Z (Zero) > Flags in der ALU. Z gesetzt = false, sonst true. Fertig. Nein! Eben gerade nicht! Das Zero-Flag ist KEINE Ganzzahl in irgend einem Register. Vielen Dank für dieses wunderbare Argument; das ist mir noch gar nicht aufgefallen: C fällt in diesem Punkt sogar hinter den Assembler zurück! > Wie gesagt: Effizienz zählt. Das hat nichts mit Effizienz zu tun, das ist einfach Stumpfsinn.
Possetitjel schrieb: > Wie krank ist denn eine Sprache, die zwar boolesche Ausdrücke > auswerten kann, aber keinen eigenen Datentyp hat, um die > Ergebnisse zu speichern?! C hat einen Datentyp dafür: _Bool. Ein normaler arithmetischer Datentyp, mit der Eigenheit, dass beim Abfragen dessen wertes immer 0 oder 1 herauskommt.
Possetitjel schrieb: > Man hätte Referenzen auch als Paare [Startadr; (Endadr+1)] > definieren können; auf diese Art könnte man den gesamten > Speicher adressieren und hätte gleichzeitig die Möglichkeit > zur Bereichsprüfung. > NIL-Referenzen wären dann einfach solche mit > "Startadr >= Endadr". Coole Idee. Und wie zeigt man auf eine einzelne Speicherzelle (ob nun 7,8,12 oder 16 mal dahingestellt)? Ein Glück daß Designer und Implemetierer von C mit einem Mindestvorat an Verstand zur Welt kamen.
Possetitjel schrieb: > Inzwischen weiss man: Verfrühte Mikrooptimierung ist > die Wurzel alles Bösen. Klaro. Inzwischen weiß man sogar, dass sich der IS nur aufgrund verfrühter Mikrooptimierung gebildet hat.
Carl D. schrieb: > Possetitjel schrieb: >> Man hätte Referenzen auch als Paare [Startadr; (Endadr+1)] >> definieren können; auf diese Art könnte man den gesamten >> Speicher adressieren und hätte gleichzeitig die Möglichkeit >> zur Bereichsprüfung. >> NIL-Referenzen wären dann einfach solche mit >> "Startadr >= Endadr". > > Coole Idee. Und wie zeigt man auf eine einzelne Speicherzelle > (ob nun 7,8,12 oder 16 mal dahingestellt)? Hä?! Das meinst Du nicht ernst?! Die Referenz (7,8) zeigt auf die einzelne Speicherzelle mit der Adresse 7. Wo ist das Problem? Die Referenz (0,1) würde auf Adresse 0 zeigen. Die Referenz (7,7) wäre NIL (genauso wie (0,0) oder (14,12)). Einziger Nachteil: Die "letzte" Adresse lässt sich nicht einzeln adressieren, sondern nur als Bestandteil einer größeren Datenstruktur, weil sich der Nachfolger nicht bilden lässt.
Johann L. schrieb: > Possetitjel schrieb: >> Inzwischen weiss man: Verfrühte Mikrooptimierung ist >> die Wurzel alles Bösen. > > Klaro. Inzwischen weiß man sogar, dass sich der IS nur > aufgrund verfrühter Mikrooptimierung gebildet hat. Vermutlich stimmt das sogar -- "America first" ist ja auch nur eine Spielart der Mikrooptimierung. Aber das gehört nich hierher.
Daniel A. schrieb: > Possetitjel schrieb: >> Wie krank ist denn eine Sprache, die zwar boolesche >> Ausdrücke auswerten kann, aber keinen eigenen Datentyp >> hat, um die Ergebnisse zu speichern?! > > C hat einen Datentyp dafür: _Bool. Ja, okay. Danke für die Korrektur. 27 Jahre nach Erfindung der Sprache kommt doch langsam die Idee auf, dass es außer Zahlen vielleicht DOCH noch andere interessante Datentypen geben könnte. > Ein normaler arithmetischer Datentyp, Das bedeutet, ich kann mit einer booleschen Variablen x problemlos x*x-x ausrechnen? > mit der Eigenheit, dass beim Abfragen dessen wertes > immer 0 oder 1 herauskommt. Naja. Besser als nix, zugegeben.
Possetitjel schrieb: > Das bedeutet, ich kann mit einer booleschen Variablen x > problemlos x*x-x ausrechnen? Ja, aber du könntest auch gleich 0 hinschreiben, ist lesbarer.
Possetitjel schrieb: > Axel S. schrieb: >> Possetitjel schrieb: >>> Wie krank ist denn eine Sprache, die zwar boolesche >>> Ausdrücke auswerten kann, aber keinen eigenen Datentyp >>> hat, um die Ergebnisse zu speichern?! >> >> Das folgt einfach der üblichen Implementierung des Z (Zero) >> Flags in der ALU. Z gesetzt = false, sonst true. Fertig. > > Nein! > Eben gerade nicht! > > Das Zero-Flag ist KEINE Ganzzahl in irgend einem Register. Das hst du auch nicht begriffen? Das Zeroflag ist ein einzelnes Bit - genau das was man zum Speichern einer booleschen Variable minimal braucht. Und die Regeln nach denen die ALU das Zeroflag setzt, sind die gleichen nach denen C den booleschen Wert einer Variable bestimmt (bis auf die Negation). Deswegen ist das in C effizient, weil es direkt auf eine ALU-Operation gemapt werden kann.
Possetitjel schrieb: > Vielleicht beschränkst Du Deine Urteile zukünftig auf > Deine eigene Jugend; da liegst Du hoffentlich weniger > oft daneben. Bei dem Unsinn, den man Dir da in Deiner Jugend erzählt haben soll.. C hat übrigens in der Tat einen breiten Anwendungsbereich. Nicht nur Mikrocontroller, sondern Linux ist auch in C. Oh, und Git als Anwendung. Das ist bewußt in C gemacht worden, weil man da wirklich auf Byte-Level programmiert hat. Der Performance wegen, die bei einem Projekt mit über 1000 Entwicklern weltweit durchaus wichtig ist. Da man häufig Pointer auf Gültigkeit prüft, ergibt es Sinn, den Wert 0 zu wählen, weil ein Test auf Gleichheit oder Ungleichheit mit 0 auf den meisten Architekturen schneller ist als gegen andere Werte. Und erst recht als ein Test von zwei verschiedenen Werten nach Deinem Vorschlag, besonders auf Architekturen mit wenig Registern. > Überzeugendster Ausdruck dieser Strömung sind die > Toten in der Silvesternacht 1999 in Berlin. Mangelhafte Doku und unklare Zuständigkeiten haben mit Performance nichts zu tun.
Nop schrieb: > C hat übrigens in der Tat einen breiten Anwendungsbereich. Natürlich. Ein Faustkeil auch. > Da man häufig Pointer auf Gültigkeit prüft, ergibt es Sinn, > den Wert 0 zu wählen, weil ein Test auf Gleichheit oder > Ungleichheit mit 0 auf den meisten Architekturen schneller > ist als gegen andere Werte. Es geht nicht darum, welchen Wert man wählt, um eine bestimmte Bedingung zu codieren -- es geht darum, dass es offenbar eine große Fraktion von Leuten gibt, denen nicht zu vermitteln ist, dass ein NIL-Pointer (ungültige Speicherreferenz) von der Bedeutung her etwas anderes ist als ein Pointer auf Speicher- adresse 0. Es ist eine Schwäche von C, dass hier das eine mit dem anderen zusammenfällt -- und weder eine technischen Notwendigkeit, noch eine tolle Errungenschaft. > Und erst recht als ein Test von zwei verschiedenen Werten > nach Deinem Vorschlag, besonders auf Architekturen mit wenig > Registern. Mein Vorschlag war sowieso schlecht: Man sollte [Startadr, Länge] wählen. Ein NIL-Pointer ist dann ganz einfach an Länge=0 zu erkennen. >> Überzeugendster Ausdruck dieser Strömung sind die >> Toten in der Silvesternacht 1999 in Berlin. > > Mangelhafte Doku und unklare Zuständigkeiten haben mit > Performance nichts zu tun. Du vergisst, dass nichts davon zum Tragen gekommen wäre, wenn man beim Erstellen der Software nicht Performance über Zuverlässigkeit gestellt hätte. Insofern: Doch, ja, das hat damit zu tun.
Axel S. schrieb: > Das hst du auch nicht begriffen? Axel, wenn Du meine Argumente schon nicht begreifst, dann verzichte doch wenigens auf Deine Arroganz. Du hast mir ein sehr gutes Argument geliefert, was eine Schwäche von C als "portablem Assembler" aufzeigt. Wenn Du Dein eigenes Argument nicht verstehst, dann kann ich damit sehr gut leben. Ich danke Dir trotzdem.
Daniel A. schrieb: > Possetitjel schrieb: >> Das bedeutet, ich kann mit einer booleschen Variablen x >> problemlos x*x-x ausrechnen? > > Ja, aber du könntest auch gleich 0 hinschreiben, ist > lesbarer. Hihi... ja, gut, meine Frage war ungünstig formuliert. Es ging mir darum, ob ich Deine Bemerkung "normaler arithmetischer Datentyp" richtig verstanden habe, denn darunter würde ich verstehen, dass ich alle arithmetischen Grundoperationen anwenden und auch Werte größer 1 zuweisen kann -- nur beim Lesen der Variablen kommt halt nur 0 oder 1 raus.
Possetitjel schrieb: > Es ist eine Schwäche von C, dass hier das eine mit dem anderen > zusammenfällt -- und weder eine technischen Notwendigkeit, noch > eine tolle Errungenschaft. Klar kann man Nil-Pointer anders realisieren. Mit entsprechend höherem Registerdruck, wie ich schon sagte. Das scheint Dir egal zu sein - C ist aber von und für Leute, denen das nicht egal ist. Nimm doch einfach Ada. > Du vergisst, dass nichts davon zum Tragen gekommen wäre, > wenn man beim Erstellen der Software nicht Performance über > Zuverlässigkeit gestellt hätte. Und? Das belegt immer noch gar nichts. Grundlagen der Aussagelogik beachten.
Nop schrieb: > Possetitjel schrieb: > >> Es ist eine Schwäche von C, dass hier das eine mit dem >> anderen zusammenfällt -- und weder eine technischen >> Notwendigkeit, noch eine tolle Errungenschaft. > > Klar kann man Nil-Pointer anders realisieren. Mit > entsprechend höherem Registerdruck, wie ich schon sagte. Mag sein, ja. Man sollte aber vielleicht beachten, dass x86 hier nicht das Maß aller Dinge ist. > Das scheint Dir egal zu sein - Nein. Dass ist Deine (etwas übertriebene) Interpretation meiner Worte. Dass mir Korrektheit und Zuverlässigkeit wichtiger sind als die letzten 20% Performance, heißt nicht, dass mir die Performance völlig egal wäre. In Zeichen: Aus K > P folgt nicht P=0 :) Die Performance ist bei der nächsten Rechnergeneration ohnehin 50% größer, ohne dass ich dafür etwas tun muss -- aber die Fehler im Programm bleiben, wie sie sind. > C ist aber von und für Leute, denen das nicht egal ist. Leider nicht nur -- denn ganz ehrlich: Welche Alternative hat man? (Beispielsweise für µC-Programmierung) > Nimm doch einfach Ada. Oberon wäre wohl naheliegender. >> Du vergisst, dass nichts davon zum Tragen gekommen wäre, >> wenn man beim Erstellen der Software nicht Performance >> über Zuverlässigkeit gestellt hätte. > > Und? Das belegt immer noch gar nichts. Doch. Die Grundlage für jegliche Bemühung um technische Zuverlässig- keit liegt in der Erkenntnis, dass es genügt, EINE EINZIGE notwendige Bedingung für die Katastrophe nicht zu erfüllen. > Grundlagen der Aussagelogik beachten. Done.
Nop schrieb: > Nimm doch einfach Ada. Geht nicht, denn darauf lässt sich nicht so einfach schimpfen. Dass C eine uralt-Sprache mit Schwächen ist steht außer Frage, denk ich. Bei allen "Argumenten" gegen C, sollte man aber immer folgenden im Blick haben. Erstens: In jeder Sprache lassen sich ungültige Programme formulieren. In manchen einfacher und intuitiver, in anderen hat man andere Möglichkeiten. Zweitens: Wenn man eine Sprache nicht berherrscht, hat man schlechte Karten. Egal wie die Sprache heißt. Wenn es — mal wieder — um C und Undefined Behaviour geht — oder Implementation Defined wie oben —, dann ist das ein treffliches Vehikel, um auf C zu schimpfen. Man kann aber auch den Standpunkt einnehmen, dass derjenige, der sowas nicht weiß, die Sprache einfach nicht beherrscht und sein Handwerkszeug nicht kennt. Das soll jetzte kein Rant auf Software-Entwickler sein, denn oft genug haben diese garnicht die Zeit, sich in die Grundlagen einzuarbeiten und kommen wie die Jungfrau zum Kind: Jemand macht ne Harware, und Software gehört "einfach dazu", sind ja nur ein paar Zeilen die da zu tippsen sind, kann jedes Script-Kiddie. Abgabe ist am besten gestern. In der Not wird das fehlende Fundament dann gerne durch das Design-Pattern "Trial & Error" ausgebügelt: Code getippt, durch den Simulator / Debugger / Testboard genudelt oder gar generierten Binärcode studiert Binary wie erwartet => Code ist valide. Fehler sind so vorprogrammiert, einhergehend entsprechender Frust und Schaden bis hin zu "Allergie gegen C" wie in einem Thread neulich. Und der Rat "Nimm C++ statt C" ist in einer solchen Situation einfach irrsinnig, denn: C++ ist i.w. eine Obermenge von C, und wenn man C nicht solide kann und deshalb den Hals auf C hat, wird man C++ nimmermehr lernen. C++ ist um Größenordnungen komplexer, es ist ein Monstrum. Wer das Konzept von UB in C nicht blickt, soll das Zusammenspiel von Templates mit Namespaces mit Mehrfachvererbung mit Lookup mit Bindings mit Overloads mit Resolutions mit XXX sicher beherrschen, sämtliche Spielarten von "ill formed, no warning required" umschiffen, dabei effizienten und wartbaren Code in endlicher Zeit produzieren können? Jo klar.
Possetitjel schrieb: > Man sollte aber vielleicht beachten, dass x86 hier nicht > das Maß aller Dinge ist. Ich schrieb nichts von x86. > Dass mir Korrektheit und Zuverlässigkeit wichtiger sind > als die letzten 20% Performance Na dann mach doch einfach in C ein Typedef und ein paar Defines, schon kannste Deine Vorstellungen auch in C umsetzen. Wenn Du hingegen an einer Sprache interessiert bist, die Dich zu so etwas zwingt, bist Du bei C grundverkehrt. > Die Performance ist bei der nächsten Rechnergeneration ohnehin > 50% größer, ohne dass ich dafür etwas tun muss Du bist hier in einem Forum für Mikrocontroller. Paar hunderttausend mal einen M0 statt eines M4, das ist merkbar. Von batteriebetriebenen Anwendungen mal ganz zu schweigen. x86 ist nicht das Maß aller Dinge. ;-) > Leider nicht nur -- denn ganz ehrlich: Welche Alternative > hat man? (Beispielsweise für µC-Programmierung) Du mußt Dich schon entscheiden, ob Du hardwarenah oder auf sehr abstraktem Niveau arbeiten willst. Sonst nimm halt statt eines M0 einfach einen Raspi und laß Ada drauf los. Rechenkraft fällt schließlich vom Himmel. Wer in C programmiert, denkt in portablem Assembler. Das war übrigens bei Git einer der Hauptgründe für C, denn Git als Anwendung ist ja keine Systemprogrammierung mehr. Wer nicht vorhat, in portablem Assembler zu denken, kann andere Sprachen wählen. >> Nimm doch einfach Ada. > > Oberon wäre wohl naheliegender. Warum, Ada ist eigens für genau Deine Bedürfnisse entworfen worden. >> Und? Das belegt immer noch gar nichts. > > Doch. Nein. Daß es Fälle gibt, in denen man zuviel Speicher gespart hat, heißt nicht, daß Speichersparen verkehrt oder nicht erstrebenswert wäre.
Johann L. schrieb: > Geht nicht, denn darauf lässt sich nicht so einfach > schimpfen. Das hat einen Unterton, der mir dann doch nicht gefällt. Ich muss C gottseidank nicht benutzen; ich bin, je nach Einzelfall, mit FreePascal oder Tcl/Tk gut bedient. Ich habe also kein Motiv, auf C zu schimpfen. > Dass C eine uralt-Sprache mit Schwächen ist steht außer > Frage, denk ich. Das sehe ich deutlich anders. Nach meinem Eindruck sind die Leute, die gleichzeitig gut in C programmieren können UND nüchtern über die Schwächen von C reden können, SEHR selten. (Zugestanden: Auf µC.net ist die Dichte etwas höher.) > Erstens: In jeder Sprache lassen sich ungültige Programme > formulieren. Klar. Steht außer Frage. > Zweitens: Wenn man eine Sprache nicht berherrscht, hat man > schlechte Karten. Du überspringst die vorgelagerte Hauptfrage: Warum sollte ich mir die Quälerei antun, diese Sprache zu lernen (außer aus nackter Not, weil es nix anderes gibt)? Auf diese Frage bekommt man i.d.R. keine sachliche Antwort. > Egal wie die Sprache heißt. Wenn es — mal wieder — um C > und Undefined Behaviour geht — oder Implementation Defined > wie oben —, dann ist das ein treffliches Vehikel, um auf C > zu schimpfen. Das will ich eigentlich gar nicht. Ich bin lediglich nicht bereit, die (aus meiner Sicht zahlreichen, kruden) Eigenarten von C als gottgegeben hinzunehmen -- oder mir gar als die Erlösung verkaufen zu lassen. Ich möchte - unabhängig davon, ob ich die Festlegung gut oder schlecht finde - verstehen, WARUM dieses oder jenes genau so festgelegt wurde. (Der Verweis auf die Originalliteratur hilft nicht weiter; ich habe eine deutsche Ausgabe des K&R zur Verfügung. Informativ, aber ziemlich zähe Lektüre.) Negatives Beispiel: Wenn mir weiter oben erzählt werden sollte, dass ich blöd bin, weil ich nicht begreife, dass boolesche Datentypen sowieso überflüssig sind, weil die CPU ja auch keinen booleschen Datentyp hat, dann hat sich der Gesprächspartner disqualifiziert. Ich weiss, was die CPU macht; ich habe schon Assembler programmiert. Positives Beispiel: Eine der vielen Krankheiten bei C finde ich die Syntax der for-Schleife. Vor einer Weile ist dieser Punkt mal diskutiert worden, und A.K. hat erklärt, dass das eine 1:1-Umsetzung bestimmter Assemblerkonstrukte ist. Ich finde die Syntax immer noch furchtbar, aber ich rege mich nicht mehr darüber auf, weil ich jetzt weiss, dass ich dieses Thema in 99% aller Fälle getrost ignorieren kann. Da steckt überhaupt keine grandiose Geheimwissenschaft dahinter, sondern das ist lediglich (wieder mal) eine Kurzschreibweise für ein Konstrukt, auf das ich gern verzichten kann. (Kann ich wirklich. tcl kennt "foreach" und "while", mehr brauche ich nicht.) > Man kann aber auch den Standpunkt einnehmen, dass derjenige, > der sowas nicht weiß, die Sprache einfach nicht beherrscht > und sein Handwerkszeug nicht kennt. Ja! Sicher! Das ist doch gar nicht das Thema! Ich weiss , dass ich C nicht beherrsche. Das Thema ist: Warum sollte es sich lohnen, die Qual auf sich zu nehmen, diese Sprache zu erlernen? Die übliche patzige Antwort "Dann lass es halt bleiben!" ist eben nur das: Eine patzige Antwort ohne Nutzwert. Ich habe in den vergangenen 30 Jahre ungefähr 3 Mal Anlauf genommen, C zu lernen, aber das ist jedes Mal steckengeblieben, weil ich mich nicht überwinden konnte, mir diesen (aus meiner laienhaften Sicht) kruden Scheiss einzutrichtern. Ich will also überhaupt nicht schimpfen; ich suche gute (!) Argumente dafür, die Sprache zu lernen. Was also ist an der Sprache so toll? Die guten Argumente bekommt man nur üblicherweise nicht -- sondern Pöbeleien, dass man halt einfach zu blöd sei, die tiefe Weisheit und Erleuchtung zu verstehen. Liebe Leute, dass ich die C-Syntax furchtbar finde, ist KEIN zwingender Beweis dafür, dass ich geistig minderbemittelt bin!
Possetitjel schrieb: > Das Thema ist: Warum sollte es sich lohnen, die Qual auf sich > zu nehmen, diese Sprache zu erlernen? Weil man damit sehr hardwarenah programmieren kann, ohne deswegen Assembler nehmen zu müssen - der wäre nicht portabel und auf jeder CPU wieder sehr deutlich anders. C wurde für diesen Anwendungsfall entworfen, und das ist auch der Grund, wieso es einiges an Unschärfe da gibt. Nehmen wir mal einen Shift eines 32-bit Integers um 32 Bit, der ist in C nicht definiert. Das kommt daher, daß unter x86-32 der Opcode für den Shiftbefehl nur 5 Bit für die Shift-Distanz hat, das reicht ja. Wenn man nun eine 1 um 32 Bit shiften will, dann sind die unteren 5 Bit 0, folglich wird gar nicht geshiftet, und es kommt 1 heraus. Auf Power-PC ist das hingegen anders, und das Ergebnis ist 0. Wollte man das nun plattformübergreifend definieren, dann müßte man je nach Plattform mit Checks arbeiten, die wiederum die Performance in den Keller ziehen würden. Es gibt so manches, was in C erstmal absurd aussieht, was aber durchaus seinen Grund hat, und zwar oftmals eben aus Hardware-Gründen. Das ist bei einer Sprache, die so dicht an die Hardware geht und gehen soll, nicht zu vermeiden. Wer da natürlich herangeht und eine ideale abstrakte Maschine erwartet, die sich überall gleich verhält die dafür dann auch langsamer sein darf, der ist mit C verkehrt und sollte lieber eine andere Sprache nehmen. Ad hoc fiele mir Java ein, was genau mit dieser Zielsetzung entworfen wurde, da hat man die Abhängigkeit von der Hardware in die VM verfrachtet.
Possetitjel schrieb: > Die guten Argumente bekommt man nur üblicherweise nicht -- > sondern Pöbeleien, dass man halt einfach zu blöd sei, die tiefe > Weisheit und Erleuchtung zu verstehen. > Liebe Leute, dass ich die C-Syntax furchtbar finde, ist KEIN > zwingender Beweis dafür, dass ich geistig minderbemittelt bin! Du bist hier im Forum "Mikrocontroller und Digitale Elektronik". Wenn wir das jetzt mal nach oben abgrenzen und nur Systeme ohne BS betrachten, dann geht an C oder/und Assembler kein Weg vorbei. Du kannst die Syntax finden wie du willst, das ist uns egal. Aber wer sich über die Syntax einer simplen for-Schleife aufregt... Da möchte ich dich gern wieder zitieren... Klar kannst du jetzt trotzig sein und dich nach Alternativen umsehen. Allerdings bist du dann auf wenige Controllertypen und in der Regel einen Hersteller der Sprache angewiesen. Das will sich keiner antun. Schon gar nicht im professionellem Bereich. Das wird dann ziemlich einsam. Die ersten Gehversuche im Controllerbereich mit C sind ja nun auch nicht so schwer. Fang von mir aus mit Arduino an. Das können sogar Kinder und Künstler. Aber wenn man mit voreingestellter Haßkappe loslegt braucht man sich nicht zu wundern.
Beitrag #5228746 wurde von einem Moderator gelöscht.
Nop schrieb: >> Dass mir Korrektheit und Zuverlässigkeit wichtiger sind >> als die letzten 20% Performance > > Na dann mach doch einfach in C ein Typedef und ein paar > Defines, schon kannste Deine Vorstellungen auch in C > umsetzen. Ich weiss nicht, was ich Dir getan habe, um diesen Zynismus zu verdienen. Wenn ich "einfach ein paar Defines" machen könnte, würden wir diese Diskussion nicht führen -- und das weisst Du natürlich auch. > Wenn Du hingegen an einer Sprache interessiert bist, die > Dich zu so etwas zwingt, bist Du bei C grundverkehrt. Da ist er wieder, der Horror des C-Programmierers, von der Sprache "gezwungen" zu werden, den einen oder anderen Fehler nicht zu machen. Du verwendest auch für alle Elektrogeräte Blankdraht, weil Du ja keinesfalls "gezwungen" werden willst, nicht versehentlich an die Phase zu packen? >> Die Performance ist bei der nächsten Rechnergeneration >> ohnehin 50% größer, ohne dass ich dafür etwas tun muss > > Du bist hier in einem Forum für Mikrocontroller. Ja. Das Argument gilt im Grundsatz auch dort. > Paar hunderttausend mal einen M0 statt eines M4, das ist > merkbar. Von batteriebetriebenen Anwendungen mal ganz zu > schweigen. x86 ist nicht das Maß aller Dinge. > ;-) Nein, natürlich nicht. -- Moore's Law gilt aber auch für µC. >> Leider nicht nur -- denn ganz ehrlich: Welche Alternative >> hat man? (Beispielsweise für µC-Programmierung) > > Du mußt Dich schon entscheiden, ob Du hardwarenah oder auf > sehr abstraktem Niveau arbeiten willst. Nein -- warum denn? Wieso ist ein boolescher Datentyp, der kein verkappter Integer ist, oder eine Speicherreferenz, die Längenprüfung zulässt, plötzlich "sehr abstrakt"? Hast Du mal in AWL programmiert? DAS ist hardwarenahe UND abstrakt. > Sonst nimm halt statt eines M0 einfach einen Raspi und laß > Ada drauf los. Rechenkraft fällt schließlich vom Himmel. Nein, das tut sie nicht. Ich weiss nicht, woher dieser Drang zur Diffamierung rührt. Natürlich soll man ökonomisch mit der Rechenleistung umgehen, aber "ökonomisch" ist eben nicht "geizig". Der sarkastische Spruch "Wir müssen sparen -- koste es, was es wolle!" trifft das ganz gut. > Wer in C programmiert, denkt in portablem Assembler. Das mag sein -- aber das hilft mir nicht weiter. Welche (reale!) Wahl habe ich, wenn ich portable System- programmierung machen will? (Forth mal bitte außen vor lassen.) >>> Nimm doch einfach Ada. >> >> Oberon wäre wohl naheliegender. > > Warum, Ada ist eigens für genau Deine Bedürfnisse entworfen > worden. Nun ja, wenn es einen Crosscompiler für MSP430 gibt, kommt es vielleicht tatsächlich in die engere Wahl... >>> Und? Das belegt immer noch gar nichts. >> >> Doch. > > Nein. Daß es Fälle gibt, in denen man zuviel Speicher > gespart hat, heißt nicht, daß Speichersparen verkehrt > oder nicht erstrebenswert wäre. Das habe ich doch auch nirgendwo behauptet. Es geht, wie schon mehrfach wiederholt, einfach um die Prioritäten. Und die liegen, meiner unmaßgeblichen Meinung nach, bei C deutlich suboptimal.
Possetitjel schrieb: > Ich will also überhaupt nicht schimpfen; ich suche gute (!) > Argumente dafür, die Sprache zu lernen. Was also ist an der > Sprache so toll? Toll? C etwa? Nee... Wohlgemerkt, wenn man C vernünftig benutzt und mit dem nötigen mentalen Abstand betrachtet, ist C eine durchaus nützliche Programmiersprache. Aber eigentlich weiß jeder ernstzunehmende C-Programmierer, daß C eine miserabel konstruierte Programmiersprache ist. Ebenso weiß auch jeder, daß alle bisherigen Versuche, sowohl von C wegzukommen als auch zugleich dabei zu bleiben, ziemliche Krücken geworden sind. Der Katzenjammer darüber ist schon seit einigen Jahren zu beobachten, auch dieses Forum ist vollgestopft mit Hilfeschreien von Eleven - aber das Ganze kommt ein bissel zu spät. Vor 20 oder besser noch vor 30 Jahren hätte man es sich eben besser überlegen sollen und es nicht zulassen dürfen, daß sich die Programmier-Szene zu einer C-Monokultur entwickelt. Eine anständige Konkurrenz hätte auch C recht gut getan. Aber das ist alles vorbei. Wer jetzt nen µC programmieren will, muß halt C oder Assembler nehmen, weil eine ernstzunehmende Alternative nicht existiert. Genau DAS ist das "tolle" an C und zugleich das einzige Argument. Denkt an Gorbatschow. Wer zu spät kommt, den bestraft das Leben. W.S. Vielleicht sollte man hier jetzt AMEN sagen. Oder?
Possetitjel schrieb: > Wenn ich "einfach ein paar Defines" machen könnte, würden wir > diese Diskussion nicht führen -- und das weisst Du natürlich > auch. Wieso, was soll denn daran das Problem sein? Das Coole an so einer Lösung wäre obendrein, daß Du diese Defines dann auch noch mit ifdefs klammern kannst und damit einen Debug-Build mit Checks und einen Release-Build ohne Checks bauen kannst. Das geht dann im Buildscript einfach als Compiler-Option rein. > Da ist er wieder, der Horror des C-Programmierers, von der > Sprache "gezwungen" zu werden, den einen oder anderen Fehler > nicht zu machen. Nein, es ist der Horror davor, zu ineffizienten Konstrukten gezwungen zu sein und die nicht nur nach Bedarf zu machen. Man macht in C schließlich auch ISRs und dergleichen. Da möchte ich schon, daß da nicht erst noch ein paar Checks im Hintergrund ablaufen, solange ich das nicht so eingerichtet habe. C veranstaltet ganz bewußt im Hintergrund keine weitere Funktionalität. Das, was Du hinschreibst, ist auch das, was Du bekommst. Wenn Du das nicht willst, kannst Du auch C++ nehmen, da gilt es heute als schlechter Stil, überhaupt noch mit raw pointers herumzumachen. Um das dann freilich noch schnell zu kriegen, mußt Du immer im Hinterkopf haben, was bei welchen Konstrukten dann alles an Rattenschwanz nachkommt. Bei C++ bezahlst Du nicht für etwas, das Du nicht bestellt hast - aber Du mußt die riesige Speisekarte exakt kennen. Ansonsten ist das mit C++ wie in einem Puff, wo zwar das Mineralwasser 2 Euro kostet, aber für das Gläschen Sekt mit der Bedienung biste 200 Euro los. Dafür haste die Garantie, daß Du mit C++ alles "safer" hast, solange Du nicht in den Keller gehst. > Nein, natürlich nicht. -- Moore's Law gilt aber auch für µC. Was nichts dran ändert, daß bei gleichem technischen Fortschritt immer noch der µC mit weniger RAM, ROM und MHz weniger Energie verbraucht und somit andere Anwendungen ermöglicht. > Wieso ist ein boolescher Datentyp, der kein verkappter > Integer ist, JEDER bool'sche Datentyp ist ein verkappter Integer, weil dabei nämlich letztlich Maschinencode rausfällt, der ein Register auf 0 testet. > oder eine Speicherreferenz, die Längenprüfung zulässt ... und den Overhead dafür auch gleich erzwingt. Ich will aber keine Längenprüfung haben, wenn ich bei memory mapped IO direkt mit einem volatile-Pointer arbeite. > Hast Du mal in AWL programmiert? Nein, bislang nichtmal davon gehört. Aber warum tust Du es dann nicht einfach? > Welche (reale!) Wahl habe ich, wenn ich portable System- > programmierung machen will? Dreh die Frage mal um: wieso meinst Du, daß eine andere Sprache, die das so ermöglicht, Dir dann besser gefiele? > Nun ja, wenn es einen Crosscompiler für MSP430 gibt, kommt > es vielleicht tatsächlich in die engere Wahl... Warte doch einfach auf Moore's Law, das gilt auch für µCs, sagtest Du gerade. > Und die liegen, meiner unmaßgeblichen Meinung nach, bei > C deutlich suboptimal. Sie liegen deutlich mehr in Richtung Performance und direkter Arbeit mit Hardware als bei vergleichbaren imperativen Sprachen. Was man durchaus kritisieren kann, das ist das Ausmaß an undefined behaviour, von dem man einen guten Teil genausogut auch als implementation defined hätte machen können. Da ist man damals zu großzügig gewesen.
W.S. schrieb: > Toll? C etwa? Nee... Naja, ich hab mit Pascal angefangen, und nach einem kleinen Demoprojekt zur Einarbeitung in C habe ich nie zurückgesehen. Das war wie Radfahren jetzt ohne Stützräder. Dennoch wäre es besser gewesen, hätte man damals nicht eine völlig nutzlose Spielzeugsprache als Pascal standardisiert, sondern etwas Richtiges - und zwar portabel und herstellerunabhängig.
Nop schrieb: > Possetitjel schrieb: > >> Das Thema ist: Warum sollte es sich lohnen, die Qual >> auf sich zu nehmen, diese Sprache zu erlernen? > > Weil man damit sehr hardwarenah programmieren kann, ohne > deswegen Assembler nehmen zu müssen - der wäre nicht > portabel und auf jeder CPU wieder sehr deutlich anders. Gut. Vorläufig akzeptiert. > [...] Nehmen wir mal einen Shift eines 32-bit Integers > um 32 Bit, der ist in C nicht definiert. > > Das kommt daher, daß unter x86-32 der Opcode für den > Shiftbefehl nur 5 Bit für die Shift-Distanz hat, das > reicht ja. Wenn man nun eine 1 um 32 Bit shiften will, > dann sind die unteren 5 Bit 0, folglich wird gar nicht > geshiftet, und es kommt 1 heraus. Auf Power-PC ist das > hingegen anders, und das Ergebnis ist 0. Okay. Soweit verstanden. > Wollte man das nun plattformübergreifend definieren, > dann müßte man je nach Plattform mit Checks arbeiten, > [...] Nicht unbedingt. Es besteht ja überhaupt kein Zwang, die Shift-Anweisung unbedingt in einen einzigen Maschinenbefehl abbilden zu müssen -- auf manchen Plattformen geht das gar nicht, weil es keinen Befehl gibt, der um mehr als 1 Bit schiebt. Zwei 16-bit-Shifts liefern auch auf x86 das Gewünschte. Ich würde ja nix sagen, wenn man mit einer Compilerdirektive zwischen einem "portablen" und einem "nativen" Modus hinundher- schalten könnte - dazu müsste es aber erstmal einen portablen Modus geben. > Es gibt so manches, was in C erstmal absurd aussieht, > was aber durchaus seinen Grund hat, und zwar oftmals > eben aus Hardware-Gründen. Das ist bei einer Sprache, > die so dicht an die Hardware geht und gehen soll, nicht > zu vermeiden. Hmm. Mag sein, dass das primär ein Problem der Lehre, der Vermittlung ist -- aber mir sind die Erklärungen, WARUM die Syntax eben genau SO aussieht, wie sie aussieht, i.d.R. deutlich zu dünn gesät. > Wer da natürlich herangeht und eine ideale abstrakte > Maschine erwartet, die sich überall gleich verhält die dafür > dann auch langsamer sein darf, Das ist zu krass formuliert, aber die Richtung stimmt schon. > der ist mit C verkehrt und sollte lieber eine andere Sprache > nehmen. Das würde ich gern -- wenn ich denn eine kennen würde. > Ad hoc fiele mir Java ein, was genau mit dieser Zielsetzung > entworfen wurde, da hat man die Abhängigkeit von der Hardware > in die VM verfrachtet. Hmm. Ja. Java ist wieder in die andere Richtung übertrieben.
Possetitjel schrieb: > Zwei 16-bit-Shifts liefern auch auf x86 das Gewünschte. Das war jetzt die einfache Variante. Beim Shift einer Konstanten um eine Konstante fällt gar kein Maschinencode heraus, das macht der Compiler schon zur Compilezeit. Interessant wird es, wenn man eine Konstante oder Variable um eine andere Variable shiftet, also etwas wie "x << y" macht. Das ginge ohne Checks nicht. Und man möchte auch nicht auf jeder Plattform den Shift in mehrere Shifts aufspalten, nur weil es Plattformen geben kann, die nur um 1 Bit shiften können. > Ich würde ja nix sagen, wenn man mit einer Compilerdirektive > zwischen einem "portablen" und einem "nativen" Modus hinundher- > schalten könnte - dazu müsste es aber erstmal einen portablen > Modus geben. Die C-Lösung ist es, den portablen und den nativen Modus zu vereinen. Portabel innerhalb dessen, was der C-Standard erlaubt. > Mag sein, dass das primär ein Problem der Lehre, der > Vermittlung ist -- aber mir sind die Erklärungen, WARUM > die Syntax eben genau SO aussieht, wie sie aussieht, > i.d.R. deutlich zu dünn gesät. Naja ob man nun geschweifte Klammern oder begin/end sagt, ist letztlich Geschmackssache. Ich bevorzuge die geschweiften Klammern, weil ich nicht die Syntax-Elemente im Weg haben will beim Lesen. > Das würde ich gern -- wenn ich denn eine kennen würde. Wenn Du Dich auf einen einzigen Compiler festlegen kannst, der aber auch für etliche Plattformen verfügbar ist, käme Free Pascal in Frage.
temp schrieb: > Du bist hier im Forum "Mikrocontroller und Digitale Elektronik". Das ist mir bewusst :) > Wenn wir das jetzt mal nach oben abgrenzen und nur Systeme ohne > BS betrachten, dann geht an C oder/und Assembler kein Weg vorbei. Ja - und meine Frage ist: Warum? > Du kannst die Syntax finden wie du willst, das ist uns egal. Das ist keine besonders gute Ausgangsposition, am Anfang der Unterhaltung zu erklären, dass einem die Beweggründe des Gesprächspartners egal sind, meinst Du nicht? > Aber wer sich über die Syntax einer simplen for-Schleife > aufregt... Da möchte ich dich gern wieder zitieren... Das ändert aber nichts am Fakt: Ich finde die Syntax grausig. > Klar kannst du jetzt trotzig sein und dich nach Alternativen > umsehen. Ja. Jeder reale Fortschritt beginnt mit Unzufriedenheit :) > Allerdings bist du dann auf wenige Controllertypen und in > der Regel einen Hersteller der Sprache angewiesen. Das will > sich keiner antun. Naja, das läuft dann auf eine ganz simple Antwort hinaus: Das Tollste an der Programmiersprache C ist, dass sie standardisiert ist. Das wäre zwar zum Kotzen -- aber immerhin eine nachvollziehbare Antwort. > Aber wenn man mit voreingestellter Haßkappe loslegt braucht > man sich nicht zu wundern. Über das Stadium bin ich hinaus. Ich habe nur keine Lust zu einer Quälerei, "weil das nun mal eben so ist" und "das nun mal eben dazugehört".
Nop schrieb: > hätte man damals nicht eine völlig > nutzlose Spielzeugsprache als Pascal standardisiert Sind wir jetzt beim C<--->Pascal Streit? Aber mal abgesehen davon, klingt mir dein Beitrag sehr nach Unwissenheit. Pascal - jedenfalls das heutige Pascal - ist weder nutzlos noch Spielzeug. Würdest du es auch nur ein klein wenig kennen, dann hättest du nicht sowas geschrieben. Also töne nicht gar so laut darüber. W.S.
W.S. schrieb: > Toll? C etwa? Nee... :) > Wohlgemerkt, wenn man C vernünftig benutzt und mit dem > nötigen mentalen Abstand betrachtet, ist C eine durchaus > nützliche Programmiersprache. Das steht außer Frage. > Aber eigentlich weiß jeder ernstzunehmende C-Programmierer, > daß C eine miserabel konstruierte Programmiersprache ist. Gut... der Deutung kann ich sogar etwas abgewinnen: Je vehementer jemand C verteidigt, desto weniger ernst ist er als Programmierer zu nehmen :) > Vor 20 oder besser noch vor 30 Jahren hätte man es sich eben > besser überlegen sollen und es nicht zulassen dürfen, daß sich > die Programmier-Szene zu einer C-Monokultur entwickelt. Eine > anständige Konkurrenz hätte auch C recht gut getan. Das ist leicht gesagt -- aber wer ist "man"? Nach meinem Gefühl standen die 90er zu sehr im Zeichen der Objektorientierung, als dass sich noch irgendjemand ernsthaft um eine prozedurale Sprache gekümmert hätte. > Aber das ist alles vorbei. Wer jetzt nen µC programmieren will, > muß halt C oder Assembler nehmen, weil eine ernstzunehmende > Alternative nicht existiert. Hmm... > Genau DAS ist das "tolle" an C und zugleich das einzige > Argument. Naja, Du bist nicht der einzige, der das so sieht. Vielleicht ist das ja tatsächlich die Antwort auf meine Frage. Wäre zwar nicht schön, aber immerhin eine verstehbare Antwort.
W.S. schrieb: > Sind wir jetzt beim C<--->Pascal Streit? Nein. > Pascal - jedenfalls das heutige Pascal - ist weder nutzlos > noch Spielzeug. Aber standardisiert ist es nicht! Es ging darum, daß Pascal als nutzlose Spielzeugsprache standardisiert wurde. Das hatte zur Folge, daß jede reale Implementation, egal ob auf Mac, ST oder DOS mit haufenweise proprietären Erweiterungen arbeitete. Nichts war zu gar nichts kompatibel, die Balkanisierung war immer ein Problem. Deswegen ist Pascal auch so abgestürzt, als Borland die Kurve nicht so richtig gekriegt hat, weil Turbo-Pascal nicht nur an Borland, sondern auch an DOS gebunden war. Unter DOS war es freilich cool, besonders ab Version 5 oder so. Kleines Schmankerl, wie sich das auch heute noch auswirkt: In Free Pascal sind globale Variablen immer implizit volatile, weil es das ganze Konzept von nicht-volatile für globale Variablen nicht gibt. Bei MicroE hingegen sind globale Variablen nicht volatile, wenn man sie nicht dazu quzalifiziert. Die Konsequenz ist ein typischer Pascal-F*ck*p: Nimm einen Quelltext für Free Pascal, der globals zwischen ISR und Applikation tauscht, nutz das mit MicroE weiter und wundere Dich, wieso das nicht geht. Das wäre nicht passiert, wenn man eine der brauchbaren Pascal-Version standardisiert hätte, völlig egal welche. Das Blöde an der ganzen Sache ist nun, daß Pascal vom ganzen Konzept her deutlich weniger maschinennah als C ausgerichtet ist und daher besser anstatt schlechter portabel sein sollte.
Nop schrieb: > Interessant wird es, wenn man eine Konstante oder Variable > um eine andere Variable shiftet, also etwas wie "x << y" > macht. Das ginge ohne Checks nicht. Da bin ich eben nicht ganz überzeugt. > Und man möchte auch nicht auf jeder Plattform den Shift in > mehrere Shifts aufspalten, nur weil es Plattformen geben > kann, die nur um 1 Bit shiften können. Muss man ja nicht. Der Compiler weiss ja, was die Plattform kann, für die er gerade kompiliert. Die Plattformen, die sich "nativ" so verhalten wie gewünscht, kommen mit einem Befehl aus; auf den anderen sind halt mehrere notwendig. >> Ich würde ja nix sagen, wenn man mit einer Compilerdirektive >> zwischen einem "portablen" und einem "nativen" Modus hinundher- >> schalten könnte - dazu müsste es aber erstmal einen portablen >> Modus geben. > > Die C-Lösung ist es, den portablen und den nativen Modus zu > vereinen. Portabel innerhalb dessen, was der C-Standard erlaubt. Hmm. Ja. -- Ich verstehe, dass das damals sinnvoll erschien, weil es viele (aus heutiger Sicht) exotische Plattformen gab und man keinesfalls unnötige Einschränkungen machen wollte. Aber die Entwicklung ist inzwischen 30 Jahre weiter. >> Mag sein, dass das primär ein Problem der Lehre, der >> Vermittlung ist -- aber mir sind die Erklärungen, WARUM >> die Syntax eben genau SO aussieht, wie sie aussieht, >> i.d.R. deutlich zu dünn gesät. > > Naja ob man nun geschweifte Klammern oder begin/end sagt, Nein -- DAS meine ich nun wirklich nicht. Ich dachte an Konstruktionen wie "(1<<5)|(1<<2)", die für den Unkundigen völlig krank aussehen, aber dennoch ihren Sinn haben. >> Das würde ich gern -- wenn ich denn eine kennen würde. > > Wenn Du Dich auf einen einzigen Compiler festlegen kannst, > der aber auch für etliche Plattformen verfügbar ist, käme > Free Pascal in Frage. Ja -- für Quasi-PC-Zeug ist das auch meine Wahl. Aber das löst das Problem mit den Mikrocontrollern nicht.
Possetitjel schrieb: > Nach meinem Gefühl standen die 90er zu sehr im Zeichen der > Objektorientierung, als dass sich noch irgendjemand ernsthaft > um eine prozedurale Sprache gekümmert hätte. Die Arbeit für C99 war doch in den 90ern. Für Pascal war die große Gelegenheit in den 80ern, bevor Unix (und damit C) sich überhaupt verbreitet hatte. Borland war damals in der Position, denn sie haben das Augenmerk auf ein praxistaugliches Pascal gelegt und hatten auch eine ziemliche Marktmacht. Aber Borland hat es vorgezogen, keinen Standard zu machen, weil sie dadurch mit jeder neuen Version von TP nach Belieben neue Features einbauen konnten und der Konkurrenz immer voraus waren. Hätte man erst standardisiert und dann implementiert, wäre der Vorsprung geringer gewesen. Im Prinzip hat Borland für ein paar Jahre Profit auf einer dann ohnehin wegbrechenden Plattform (DOS) Pascal geopfert. Was dann 1990 als ISO-Pascal aktualisiert wurde, war nach wie vor ein Witz.
Possetitjel schrieb: > Die Plattformen, die sich "nativ" so verhalten wie gewünscht, > kommen mit einem Befehl aus; auf den anderen sind halt mehrere > notwendig. Tja, und damit hätte man für x86 mehrere Befehle gebraucht. Nicht, daß das der spezifische Grund war, denn C gab's schon Jahre früher, aber die Entscheidung war, daß Performance wichtiger ist als ein Shift um mehr als die Variablenbreite, der auf vielen CPUs sowieso nicht existiert. > Aber die Entwicklung ist inzwischen 30 Jahre weiter. Mal den Befehlssatz für ARM Cortex-M4 angesehen? Dort findet man für die Shift-Befehle um einen fixen Betrag immer noch genau diese Begrenzung. > Nein -- DAS meine ich nun wirklich nicht. Ich dachte an > Konstruktionen wie "(1<<5)|(1<<2)", die für den Unkundigen > völlig krank aussehen, aber dennoch ihren Sinn haben. Also das ist aber auch schlechter Stil, die 5 und die 2 sollte man durch vernünftige defines ersetzen, sonst weiß man zwei Wochen danach selber nicht mehr, was das sollte. > Ja -- für Quasi-PC-Zeug ist das auch meine Wahl. Aber das > löst das Problem mit den Mikrocontrollern nicht. Free Pascal gibt's doch auch für Microcontroller. Jetzt nicht für alle und jeden, aber für etliche, und das wird besser.
Nop schrieb: > Possetitjel schrieb: > >> Wenn ich "einfach ein paar Defines" machen könnte, würden >> wir diese Diskussion nicht führen -- und das weisst Du >> natürlich auch. > > Wieso, was soll denn daran das Problem sein? Eventuell die Tatsache, dass ich die Programmiersprache C nicht beherrsche? >> Da ist er wieder, der Horror des C-Programmierers, von der >> Sprache "gezwungen" zu werden, den einen oder anderen Fehler >> nicht zu machen. > > Nein, es ist der Horror davor, zu ineffizienten Konstrukten > gezwungen zu sein und die nicht nur nach Bedarf zu machen. Nein, warum denn. Ich sage ja nicht, dass es NUR überwachte Referenzen geben soll -- meine Aussage war nur, dass es die AUCH geben sollte. Und ein echt boolescher Datentyp würde gar nix zur Laufzeit kosten, denn die Zuweisungen prüft der Compiler zur beim Übersetzen. > Wenn Du das nicht willst, kannst Du auch C++ nehmen, da > gilt es heute als schlechter Stil, überhaupt noch mit > raw pointers herumzumachen. Habe ich ernsthaft erwogen. Aber ehrlich: Mit C++ anfangen, wenn man nicht mal C kann?! >> Nein, natürlich nicht. -- Moore's Law gilt aber auch >> für µC. > > Was nichts dran ändert, daß bei gleichem technischen > Fortschritt immer noch der µC mit weniger RAM, ROM > und MHz weniger Energie verbraucht und somit andere > Anwendungen ermöglicht. Jein. Mehr RAM und ROM geht primär auf den Preis; mehr MHz geht tatsächlich auf die Energie. Es spielt also eine Rolle, ob die zusätzlichen Features der Sprache eher zusätzliche Zeit oder zusätzlichen Speicher erfordern. >> Wieso ist ein boolescher Datentyp, der kein verkappter >> Integer ist, > > JEDER bool'sche Datentyp ist ein verkappter Integer, weil > dabei nämlich letztlich Maschinencode rausfällt, der ein > Register auf 0 testet. Nee. Test auf Gleichheit kann ich über beliebigen Elementen definieren, dass ist kein Vorrecht der Arithmetik. Ein Byte im Speicher wird erst dadurch zur Zahl, dass zahlentypische Operationen damit erlaubt sind. Wenn der Compiler das per Typprüfung verbietet, ist es keine Zahl. >> Hast Du mal in AWL programmiert? > > Nein, bislang nichtmal davon gehört. Aber warum tust Du > es dann nicht einfach? Das ist SPS-spezifisch (und das will man auch nicht wirklich.) Ich habe das nur als Beispiel angeführt, weil das einerseits wildes Bitgefrickel ist (soll heißen: einzelne Bits einlesen, AND/OR/NOT, Einzelbits schreiben, "Timer" laufen lassen usw.) und andererseits vollkommen von der realen Steuerungshardware entkoppelt ist. >> Welche (reale!) Wahl habe ich, wenn ich portable System- >> programmierung machen will? > > Dreh die Frage mal um: wieso meinst Du, daß eine andere > Sprache, die das so ermöglicht, Dir dann besser gefiele? Weil ich keinen logischen Zusammenhang sehe zwischen den Eigenschaften von C, die mich stören, und der Eignung zur Systemprogrammierung: - Vernünftiges Typsystem wäre wünschenswert. Schließt ja nicht aus, dass man das per Schlüsselwort außer Kraft setzen kann, wenn das (z.B. für Hardwarezugriff) notwendig ist. Boolescher Datentyp, Pascal-Typecasts (x:=word(y);) inclusive. - Nur arithmetische Ausdrücke haben einen Wert, Anweisungen nicht. - Verzicht auf die irrsinnigen Vorrangregeln; als Ausgleich logisch nachvollziehbare Behandlung von Klammern. - überwachte Speicherreferenzen zusätzlich zu rohen Zeigern. Nur mal als Anfang. >> Nun ja, wenn es einen Crosscompiler für MSP430 gibt, kommt >> es vielleicht tatsächlich in die engere Wahl... > > Warte doch einfach auf Moore's Law, das gilt auch für µCs, > sagtest Du gerade. ??? Moore's Law macht die Hardware schneller -- aber die Software nicht portabler. >> Und die liegen, meiner unmaßgeblichen Meinung nach, bei >> C deutlich suboptimal. > > Sie liegen deutlich mehr in Richtung Performance und direkter > Arbeit mit Hardware als bei vergleichbaren imperativen Sprachen. Gut, darauf können wir uns sogar einigen. Die Schwächen von C wären mir völlig egal, wenn es eine Alternative gäbe, die genauso portabel ist wie C, aber einige seiner Schwächen nicht hat. Der Preis dürfte gern ein (moderater!) Performance- nachteil sein.
Possetitjel schrieb: > Ich würde ja nix sagen, wenn man mit einer Compilerdirektive > zwischen einem "portablen" und einem "nativen" Modus hinundher- > schalten könnte - dazu müsste es aber erstmal einen portablen > Modus geben. Genau das hast du mit C doch. Der Standard unterscheidet zwischen - specified ("portabel") - implementation-defined ("native") - undefined ("verboten") > Mag sein, dass das primär ein Problem der Lehre, der > Vermittlung ist -- aber mir sind die Erklärungen, WARUM > die Syntax eben genau SO aussieht, wie sie aussieht, > i.d.R. deutlich zu dünn gesät. Syntax ist in aller Regel persönlichen Vorlieben geschuldet. Der eine mag geschweifte Klammern (auf einer US-Tastatur kein Thema), der andere bevorzugt begin/end (auf einer deutschen Tastatur weniger Fingerverrenkungen). Manche Sprachen deklarieren Variablen mit "int abc", andere mit "abc : int". Letzteres vereinfacht das Parsing, ist ansonsten aber äquivalent. Jede Schleife kann als while-Schleife dargestellt werden, und die for-Schleife in C ist nur syntaktischer Zucker, um die häufigste Form davon (die Zählschleife) kompakt hinzuschreiben. Gleichzeitig ist die Schreibweise mächtig genug, um auch durch Listen/Bäume zu iterieren. In Perl gibt es fast nur syntaktischen Zucker, was die Sprache gut zu schreiben und schlecht lesbar macht. In Python ist das umgekehrt. Wähle deine Präferenz. Ich wüsste gerne, was genau dein Problem mit C ist, außer dass du es hasst. Nicht alles, was man nicht versteht, ist idiotisch und nicht alles, was idiotisch ist, war es immer. Und Unwissenheit verführt zu vielem.
Possetitjel schrieb: > Eventuell die Tatsache, dass ich die Programmiersprache C > nicht beherrsche? Hm ja, das leuchtet ein. > Weil ich keinen logischen Zusammenhang sehe zwischen den > Eigenschaften von C, die mich stören, und der Eignung zur > Systemprogrammierung: > - Vernünftiges Typsystem wäre wünschenswert. Schließt ja > nicht aus, dass man das per Schlüsselwort außer Kraft setzen > kann, wenn das (z.B. für Hardwarezugriff) notwendig ist. > Boolescher Datentyp, Pascal-Typecasts (x:=word(y);) inclusive. > - Nur arithmetische Ausdrücke haben einen Wert, Anweisungen nicht. > - Verzicht auf die irrsinnigen Vorrangregeln; als Ausgleich > logisch nachvollziehbare Behandlung von Klammern. > - überwachte Speicherreferenzen zusätzlich zu rohen Zeigern. > Nur mal als Anfang. Mit der Wunschliste würde ich definitiv Pascal empfehlen, und hier Free Pascal. Erstens kostet das nichts, zweitens gibt es das auch auf dem PC, und drittens gibt's ne aktive Community. Die ersten Gehversuche in einer Sprache würde ich nicht auf einem Controller machen. Besondere Performance-Einbußen würde ich im Normalfall nicht erwarten. Die Kernfrage ist, wie sehr Du auf Deinen Controller abonniert bist. Für ARMs ginge das. Was Du mit nicht-C verlierst, ist der Zugang zur lingua franca, zu der Pascal es wegen der Standardisierungs-Problematik nicht gebracht hat.
Possetitjel schrieb: > Eventuell die Tatsache, dass ich die Programmiersprache C > nicht beherrsche? Das macht es natürlich schwieriger, die positiven Seiten zu sehen. ;-) > Nein, warum denn. Ich sage ja nicht, dass es NUR überwachte > Referenzen geben soll -- meine Aussage war nur, dass es die > AUCH geben sollte. Die gibt es mit C++ und sie kommen mit einem Preisschild. > Und ein echt boolescher Datentyp würde gar nix zur Laufzeit > kosten, denn die Zuweisungen prüft der Compiler zur beim > Übersetzen. Ein echt boolescher Datentyp ist seit C99 vorhanden. Wenn du in C einen integer boolsch benutzt, nutzt der Compiler die bei der ALU ohnehin anfallenden Flags, um sie zu implementieren. Nutzt du einen echten Boolean, wird zusätzlicher Code generiert, um sicherzustellen, dass der Registerwert exakt 0 oder 1 ist. Das steht auf dem Preisschild. > Habe ich ernsthaft erwogen. Aber ehrlich: Mit C++ anfangen, > wenn man nicht mal C kann?! Modernes C++ (das heißt C++11 und neuer!) hat mit klassischem C eigentlich nichts gemeinsam. Schau es dir einfach mal an. >> JEDER bool'sche Datentyp ist ein verkappter Integer, weil >> dabei nämlich letztlich Maschinencode rausfällt, der ein >> Register auf 0 testet. > > Nee. > Test auf Gleichheit kann ich über beliebigen Elementen > definieren, dass ist kein Vorrecht der Arithmetik. Ja, das kannst du, und je nachdem, wie allgemein du deine Elemente definierst, sind deine Tests beliebig kompliziert. Aber am Ende kommt ein "ist gleich" oder ein "ist nicht gleich" heraus. Die Darstellung dessen innerhalb der CPU ist in der Regel ein Registerwert, den man effizient auf 0 testen kann und daher auch auf 0 testen möchte. > Ein Byte im Speicher wird erst dadurch zur Zahl, dass > zahlentypische Operationen damit erlaubt sind. Wenn der > Compiler das per Typprüfung verbietet, ist es keine Zahl. Eine CPU kennt grundsätzlich nur einen Datentyp, nämlich "Register der Wortbreite", selten ein wenig mehr. Dessen direkte Bedeutung ist durch die Maschinenbefehle festgelegt und lässt wenig Raum für Interpretationen. Alles, was darüber hinausgeht, kommt mit einem Preisschild. >>> Welche (reale!) Wahl habe ich, wenn ich portable System- >>> programmierung machen will? >> >> Dreh die Frage mal um: wieso meinst Du, daß eine andere >> Sprache, die das so ermöglicht, Dir dann besser gefiele? > > Weil ich keinen logischen Zusammenhang sehe zwischen den > Eigenschaften von C, die mich stören, und der Eignung zur > Systemprogrammierung: > - Vernünftiges Typsystem wäre wünschenswert. Schließt ja > nicht aus, dass man das per Schlüsselwort außer Kraft setzen > kann, wenn das (z.B. für Hardwarezugriff) notwendig ist. > Boolescher Datentyp, Pascal-Typecasts (x:=word(y);) inclusive. Das Typsystem von C orientiert sich am Typsystem der CPU. Schau dir C++ an, das ist da wesentlich ergiebiger. Typecasts in C erzwingen nur eine bestimmte Interpretation eines Datentypen. > - Nur arithmetische Ausdrücke haben einen Wert, Anweisungen nicht. Was meinst du damit? Gib mal ein Beispiel für eine Anweisung, die in C einen Wert hat, aber sinnvollerweise keinen haben sollte. > - Verzicht auf die irrsinnigen Vorrangregeln; als Ausgleich > logisch nachvollziehbare Behandlung von Klammern. Irgendwelche Vorrangregeln muss es geben. Mag sein, dass die von C gewählten suboptimal sind, aber das ist historisch so gewachsen. Alternativ kann man das auch wie in Perl machen, wo sowohl "||" als auch "or" existieren, so dass man sich als Programmierer das aussuchen kann, was man will. Das macht den Code allerdings schlechter lesbar, kommt also ebenfalls mit Preisschild. > - überwachte Speicherreferenzen zusätzlich zu rohen Zeigern. Wirf einen Blick auf C++. > Moore's Law macht die Hardware schneller -- aber die Software > nicht portabler. Sie erlaubt dir aber eine wesentlich abstraktere Sicht auf die Hardware, wodurch sie portabler wird. Siehe Java. > Die Schwächen von C wären mir völlig egal, wenn es eine Alternative > gäbe, die genauso portabel ist wie C, aber einige seiner Schwächen > nicht hat. Der Preis dürfte gern ein (moderater!) Performance- > nachteil sein. Du kommst mit C++ recht nah an die Portabilität von C heran, und die Performance-Nachteile kannst du - wenn du weißt, was du tust - weitestgehend vermeiden. Allerdings kommen die Features, die du möchtest, mit ihrem Preisschild und die Abwägung ist allein deine. Ein Hauptgrund für die Portabilität von C ist übrigens gerade die Freiheit der Sprachdefinition. Sie macht den Einsatz auf vielen exotischen Architekturen erst möglich, und jede darüber hinausgehende Spezifikation würde das verhindern (oder so verteuern, dass es nicht lohnt). Daher gibt es keine "genauso portable" Sprache wie C, außer C selbst.
Possetitjel schrieb: > Nop schrieb: > >> Interessant wird es, wenn man eine Konstante oder Variable >> um eine andere Variable shiftet, also etwas wie "x << y" >> macht. Das ginge ohne Checks nicht. > > Da bin ich eben nicht ganz überzeugt. Bleiben wir mal bei x86 und 5 Bits für den Shift-Offset, und nehmen an, dass dessen Barrel-Shifter eine 5-Bit Eingabe hat, egal ob die Eingabe aus einem Register oder einem Immediate stammt. Ein x << var müsste dann vom Compiler umgesetzt werden wie
1 | IF var > 31 |
2 | result := 0 |
3 | ELSE
|
4 | result := x << var |
mit einer naheliegenden Semantik für Shifts > 31 Bit. Und der nächste fände es unpraktisch, dass Shifts mit negativem Offset nicht funktionieren, und warum ein Links-Shift mit negatitem Offset nicht zu einem Recht-Shift führt, warum ein Rechts-Shift mit negativem Offset nicht zu einem entsprechenden Links-Shift etc. Hier ist es wie im "normalen" Leben auch: An bestimmten Stellen muss man eine Entscheidung treffen, und egel wie man sich entscheidet, hätte die andere Alternative auch ihre positiven Seiten. Aber sich garnicht zu entscheiden ist noch viel übler. Und dann sieh's mal so: Wenn sich K&R damals dafür entschieden hätten, die Semantik so zu gestalten, dann würden wir vielleicht hier und heute darüber diskutieren, warum eine Sprache, die angetreten ist effizienten Code zu generieren, so ein Unsinn verlangt: "In meiner Anwendung sind die Offsets per Konstruktion immer < 32, warum erzeugt der bescheuerte C-Compiler dennoch so'n Schrott-ineffizienten Code?" würde dann lamentiert. Oder diese andere Semantik hätte dazu geführt haben können, dass C heute keine Rolle mehr spielte. Weiß man's? Schließlich ist zu bedenken, dass die Sprache um 1970 entstand und entworfen wurde. Das sind run 45 Jahre. Durch 18 Monate (1 Moore-Einheit) sind das 30 Moore-Einheiten, d.h. damals war die Hardware 2^30 mal langsamer. Muss man sich mal auf der Zunge zergehen lassen: 2^30 (ich hab's extra in 'nen Tschenrechenr getippst: 45 : 1.5 ist wirklich 30). Und mit 24 Monaten für 1 Moore ist der Faktor immer noch 6.000.000. Jetzt takte deinen AVR oder MSP430 oder x86_64 Boliden mal um den Faktor 6.000.000 bis 1.000.000.000 langsamer und gib ihm nur 1/1.000.000.000 bis 1/6.000.000 des Speichers und dann reden wir nochmal :-) >>> Ich würde ja nix sagen, wenn man mit einer Compilerdirektive >>> zwischen einem "portablen" und einem "nativen" Modus hinundher- >>> schalten könnte - dazu müsste es aber erstmal einen portablen >>> Modus geben. >> >> Die C-Lösung ist es, den portablen und den nativen Modus zu >> vereinen. Portabel innerhalb dessen, was der C-Standard erlaubt. > > Hmm. Ja. -- Ich verstehe, dass das damals sinnvoll erschien, > weil es viele (aus heutiger Sicht) exotische Plattformen gab > und man keinesfalls unnötige Einschränkungen machen wollte. > > Aber die Entwicklung ist inzwischen 30 Jahre weiter. S einfach ist das mit einem Schalter auch nicht, wenn dann hätte man für jeden Schalter 2 Ausprägungen der (Standard)-Bibliotheken: Eine "sichere" und eine "schnelle", und das für jeden möglichen Schalter der das ABI oder die Semantik beeinflusst. Ein Faktor, warum sich C so lange hat halten können, ist bestimmt auch, dass es eben nicht in zig Varianten und Dialekte zersplitterte. > Nein -- DAS meine ich nun wirklich nicht. Ich dachte an > Konstruktionen wie "(1<<5)|(1<<2)", die für den Unkundigen > völlig krank aussehen, aber dennoch ihren Sinn haben. hihi, ich mal mir grad aus, wie C aussähe wenn es im Zeitalter von Touchscreen, Autokorrektur und Emojis entstanden wäre. Possetitjel schrieb: > Ich bin lediglich nicht bereit, die (aus meiner Sicht zahlreichen, > kruden) Eigenarten von C als gottgegeben hinzunehmen [...] > Ich möchte - unabhängig davon, ob ich die Festlegung gut > oder schlecht finde - verstehen, WARUM dieses oder jenes > genau so festgelegt wurde. puh, da musst du Ritchie fragen, wenn dir der Weg zu ihm (und zurück) nicht zu weit ist. Ein Aspekt war jedenfalls auch die wesentlich beschränktere Hardware — nicht nur die der Targets, sondern auch die der Hosts und der Build-Umgebung, auf der ein C-Compiler zu laufen hatte. Stell dir vor, du sollst einen C-Compiler schreiben in einer Sprache, die noch weniger kann als C, auf einer Maschine, die um o.g. Faktoren weniger leistungsfähig ist wie heutige Boliden was RAM, ROM und Speed angeht. Ritch ist bestimmt nicht für 9 Monate in Klausur in ein Kloster gegangen und ist dann mit dem heiligen Gral "C" zurückgekehrt, sondern er hat bestimmt auch eine Implementation gemacht und Erfahrungen daraus in Syntax und Semantik von C einfließen lassen. Um C zu verstehen genügt es m.E. nicht, nur die Entwicklung nach C sich anzuschauen und die Schwächen und Lücken, sondern man muss zum Verständnis auch einen Blick zurück auf die C-Vorgänger wie B machen, und inwieweit C in Bezug auf diese einen Fortschritt und eine Entwicklung darstellte. > Das Thema ist: Warum sollte es sich lohnen, die Qual auf sich > zu nehmen, diese Sprache zu erlernen? Wenn du bereits mit "Qual" reingehst, kann das m.E. nix werden. Damit wirst du bestenfalls zum c-hater No. 2 > Ich habe in den vergangenen 30 Jahre ungefähr 3 Mal Anlauf > genommen, C zu lernen, aber das ist jedes Mal steckengeblieben, > weil ich mich nicht überwinden konnte, mir diesen (aus meiner > laienhaften Sicht) kruden Scheiss einzutrichtern. Die erste Frage ist, ob du es lernen musst wegen Job oder warum. Wenn es "Nur" für Hobby oder Bastel ist, kann man sich auch eine Hardware suchen, in der es mehr Auswahl und Alternativen gibt wie Basic oder so. Und dann: Etwas neues ist erst mal das: neu. Es ist ungewohnt und nicht so gewohnt wie die alten, bequemen ausgelatschten Schalppen. Txet und Cdoe nmimt man nciht als einlnzee Bcuhsebatn whar, snredon als Geanzs, wie ein Blid. Nur dshealb knan man dseien Txet leesn — wnen acuh mit etaws Mhüe. Bereits ein anderer Coding-Style (Einrückungen, Groß-Kleinschreibung, CanmelCase, (nicht-)Verwendung von Spaces) kann die Lesbarkeit massiv verändern wenn man dies nicht gewohnt ist — und zwar bei einer Sprache, die man bereits kann. Bei einer neuen Sprache, die visuell komplett anders rüberkommt wie "{" anstatt "begin" ist das erst mal der Hammer. > ich suche gute (!) Argumente dafür, die Sprache zu lernen. Was > also ist an der Sprache so toll? Gegenfrage: Welches Problem willst du damit lösen? Mein Hassgegner ist C++, wegen der abartigen Komplexität und der Intransparenz. Aber neulich hab ich noch was mit C++ gemacht. Hilfreich ist auf jeden Fall, keinen Druck zu haben, ein Aufgabe, an der man Interesse hat und wo man den Grad der Drohnung selbst bestimmen kann. Und ich bin echt heilfroh, auf Arbeit nicht mit irgendwelchen C++ Aposteln (oder sonstigen) zusammenarbeiten zu müssen. Ich verwende C, Assembler, C++, Java, Python, JavaScript je nach Gusto, für Hobby, um mir selber zuzuarbeiten oder für irgendwelche Nerd-Hacks. Aber ohne Motivation und zu lösendes "Problem" käm mir glcub nie in den Sinn, ne Sprache lernen zu wollen. > Liebe Leute, dass ich die C-Syntax furchtbar finde, ist KEIN > zwingender Beweis dafür, dass ich geistig minderbemittelt bin! Wie gesagt, sie Syntax ist gar nicht sooo anders: Ausdrücke, Blöcke, Schleifen, If-Else, Funktionen, Variablen. Ob ich eine Variable als "int x" oder "x : integer" angebe ist jetzt nicht wirklich das Killerkriterium. Ja, es nervt wenn man nicht weiß "muss ich jetzt : oder ; oder ," aber das ist Übung. Und wie gesagt, es ist einfach auch ein visuelles Ding. Und manches ist einfach komisch. Isso. Ich mach mir auch keine Gedanken darüber, warum es DER Löffel heißt, aber DIE Gabel und DAS Messer. Jemand, der Deutsch lernt, begreift das schlichtweg nicht und rauft sich die Haare drüber aus. Ein Muttersprachler nimmt es noch nichtmal wahr...
Nop schrieb: > Bei C++ bezahlst Du nicht für etwas, das Du nicht bestellt hast - aber > Du mußt die riesige Speisekarte exakt kennen. Ansonsten ist das mit C++ > wie in einem Puff, wo zwar das Mineralwasser 2 Euro kostet, aber für das > Gläschen Sekt mit der Bedienung biste 200 Euro los. > > Dafür haste die Garantie, daß Du mit C++ alles "safer" hast, solange Du > nicht in den Keller gehst. Das ist der Grund dafür, dass es eine ganze Menge Stimmen gibt, die sagen: "stop teaching C". Leider wird dieser Spruch von Kate Gregory oft falsch verstanden. Er bezieht sich nämlich nicht auf C, sondern auf C++, und meint, man solle aufhören, in C++ so wie in C zu programmieren. Und das wäre in der Tat gut so ... Allerdings sind die meisten aktuellen Bücher, Kurse, etc. nicht dazu geeignet, einen anderen Stil zu propagieren. Und vielen Leuten ist es viel zu anstrengend, lange über Typ-Systeme bzw. Algebren nachzudenken. Stattdessen: alles ist ein int oder ein String, das passt schon ... Dabei ist die Abstraktionsmöglichkeit, die man in C++ hat, tatsächlich zero-overhead. Nur viele trauen dem Compiler irgendwie nicht: der echte Mann denkt halt immer noch, dass ein shift in C/C++ schneller sei als eine Multiplikation. Archaisch ... Das Ergebnis des Compilers kann halt immer nur so gut sein wie die Abstraktion des Programmierers. Und da sich die Abstraktion eines Problems in den ADTs (der algebraischen Struktur) manifestiert, ist das der entscheidende Faktor. Und gerade in diesem Aspekt (Schaffung eines domänenspezifischen Typsystems und Typ-Manipulation) ist C++ m.E. derzeit unschlagbar ...
Wilhelm M. schrieb: > Und gerade in diesem Aspekt (Schaffung eines > domänenspezifischen Typsystems und Typ-Manipulation) Vorsicht mit dem Hang zu DSLs. Die sind für das Problem zwar effizient, schaffen aber effektiv Inseln. Daran ist schon LISP gescheitert. Wenn ich mir so manche Betrachtungen zu C++ hier durchlese, erinnert mich das schon an "The Bipolar Lisp Programmer": http://www.marktarver.com/bipolar.html C++ bekommt langsam auch noch ein anderes Problem von Lisp: Was in anderen Sprachen technische Probleme sind, wird in C++ langsam zu einem sozialen Problem. Naturgemäß sind insbesondere die Überflieger sich einer solchen Problematik weder bewußt, noch können sie sie handhaben.
S. R. schrieb: > Possetitjel schrieb: >> Ich würde ja nix sagen, wenn man mit einer Compilerdirektive >> zwischen einem "portablen" und einem "nativen" Modus hinundher- >> schalten könnte - dazu müsste es aber erstmal einen portablen >> Modus geben. > > Genau das hast du mit C doch. Jein. > Der Standard unterscheidet zwischen > - specified ("portabel") > - implementation-defined ("native") > - undefined ("verboten") Eine bestimmte Sprachkonstruktion fällt aber immer in genau eine (und immer nur diese eine) Klasse, und ich muss für jedes Konstrukt WISSEN, welche Klasse das ist. Ich hatte aber im Sinn, dass man per Direktive im Quelltext wählen kann, welche genaue Bedeutung dasselbe Sprachkonstrukt haben soll. Das hätte den Vorteil, dass ich nicht den gesamten Standard im Kopf haben muss, weil nämlich im Quelltext explizit geschrieben steht, welche Variante jetzt zum Tragen kommt. >> Mag sein, dass das primär ein Problem der Lehre, der >> Vermittlung ist -- aber mir sind die Erklärungen, WARUM >> die Syntax eben genau SO aussieht, wie sie aussieht, >> i.d.R. deutlich zu dünn gesät. > > Syntax ist in aller Regel persönlichen Vorlieben geschuldet. Ja -- aber nicht nur. Natürliche Sprachen enthalten alle eine erhebliche Redundanz. Wo ist diese Redundanz bei "*(++(x*--))"? Und wo bei "x=(y==z))"? > In Perl gibt es fast nur syntaktischen Zucker, was die > Sprache gut zu schreiben und schlecht lesbar macht. In > Python ist das umgekehrt. Wähle deine Präferenz. Tcl. -- Nettes Beispiel :) Zur Erläuterung: Ich bin zu Tcl gekommen wie die Jungfrau zum Kind, nämlich durch eine Kette von Zufällen. Bei Tcl geblieben bin ich a) weil es Tk gibt und b) weil Tcl Listen, "foreach" und reguläre Ausdrücke kennt. Perl und Python waren damals (vor 20 Jahren) in der engeren Wahl; Perl fiel wegen Unlesbarkeit durch, und an Python hat mich die Einrückerei gestört. Tcl hat nur durch reinen Zufall gewonnen. Den Python/Tk-Quelltext, den ich neulich gesehen habe, fand ich lesbar, aber ziemlich unschön. > Ich wüsste gerne, was genau dein Problem mit C ist, Hmm. Ich möchte die Portabilität von C ohne die Macken von C. Gewisse Einbußen in der Performance wären akzeptabel. Die ganze Esoterik der L-Values, die dreizehn Vorrangebenen für Operatoren, die kranke Syntax sind nicht akzeptabel. > außer dass du es hasst. Nein, das stimmt nicht. Ich bin nur allergisch auf C-Apologeten und C-Missionare. Ich habe überhaupt nix gegen C -- solange ich nicht gezwungen bin, es zu verwenden. (Soll heißen: Auch wenn ich nicht wirklich verstehe, WOFÜR es gut ist, gestehe ich doch zu, DASS es für irgend etwas gut ist.) > Nicht alles, was man nicht versteht, ist idiotisch und > nicht alles, was idiotisch ist, war es immer. Na logisch -- das ist ja gar nicht meine Aussage. Ich kann durchaus nachvollziehen, warum Brian Kernighan und Dennis Ritchie die eine oder andere Entscheidung genau SO und nicht anders getroffen haben. Ich verstehe nur nicht, warum wir das heute -- 45 Jahre später -- immer noch genauso machen müssen. Schließlich kommt auch niemand auf die Idee, seinen Ruhmkorffschen Apparat in Funktion zu setzen, wenn er abends sein Zimmer erhellen möchte :)
Nop schrieb: > Wilhelm M. schrieb: > >> Und gerade in diesem Aspekt (Schaffung eines >> domänenspezifischen Typsystems und Typ-Manipulation) > > Vorsicht mit dem Hang zu DSLs. Ein paar domänenspezifische DT sind noch keine DSEL! Aber sie können verhindern, das Raumsonden verloren gehen ... > C++ bekommt langsam auch noch ein anderes Problem von Lisp: Was in > anderen Sprachen technische Probleme sind, wird in C++ langsam zu einem > sozialen Problem. Naturgemäß sind insbesondere die Überflieger sich > einer solchen Problematik weder bewußt, noch können sie sie handhaben. Ich sehe eher, dass C++ aus Kompatibilitätsgründen viele problematische old-school Konstrukte ermöglicht, die auch gerade einem Anfänger das Leben schwer machen können (deswegen: stop teaching C (if you teach C++)). Und zum anderen ist es eine Sprache, die sehr lange existiert mit demzufolge einer teilweise mitgealterten User-Gemeinde mit eingeübten Idiomen, die sich neuen Stilen/Idiomen/Pattern nur schwer öffnet. Auf den aktuellen Konferenzen ist das zum Glück anders: viele junge Leute mit extrem spannenden, weil unkonvetionellen (im Wortsinn) Ansätzen.
Wilhelm M. schrieb: > den aktuellen Konferenzen ist das zum Glück anders: viele junge Leute > mit extrem spannenden, weil unkonvetionellen (im Wortsinn) Ansätzen. Auf Konferenzen. oO Paralleluniversum. Die Realität: obwohl C weitaus kompakter ist, hat auch das schon Probleme, und die Antwort darauf war Misra-C zum Subsetting. Nein, die Antwort war nicht, nur noch Language-Lawyer einzustellen, weil denen das Domänenwissen fehlt. Und wenn sie es doch haben, dann haste Rockstar-Programmierer, die erstens teuer sind und zweitens zuwenige. Bei C++ wird auch Subsetting betrieben, aber überall anders und nicht standardisiert. Die Folge ist eine Erosion des Subsettings. Sei es, weil man tatsächlich etwas außer dem Subset sinnvoll einsetzen kann, oder ganz profan zum Angeben, weil jemand ein cooles Feature aufgeschnappt hat. Die Folge ist, daß die Maintenance-Programmierer zusehends fluchen, weil die am Ende die Obermenge kennen müssen, und zwar soweit, daß sie den Kram noch debuggen können. Zudem hast Du bei C++ außer den Experten, die tatsächlich wissen, was für Maschinencode rausfällt, die viel zahlreicheren, die das nicht wissen, sondern die effektiv guesstimate-programming betreiben. Sie wissen ungefähr, was wie funktioniert, mehr auch nicht. Ein Phänomen, was man ansonsten gerne Java-Programmierern vorwirft. Diese Art von C++-Programmierern hat Torvalds übrigens mit seinem bekannten Rant gemeint. Und nein, diese Leute werden nicht ihre komplette Freizeit damit verbingen, mit dem neusten Standard mitzuhalten. Es gibt nämlich auch Menschen, die sowas wie Freunde oder gar Familie haben, oder Interessen außerhalb vom Programmieren. Kurzum, normale Leute, deren Teamfähigkeit eben deswegen auch schon ein wichtiger Faktor ist. Du hast übrigens gerade sehr schön vorgeführt, was ich meinte. Du scheinst Dich mit C++ sehr gut auszukennen und hast sichtlich überhaupt nichts damit anfangen können, was ich mit den sozialen Problemen meinte. Auf Konferenzen. Ja nee, ist klar.
Wilhelm lass es einfach. Dieser Thread ist nur noch dazu da, alt eingesessene "Wahrheiten" vorzutragen. Nutz deine Zeit für spannende neue Dinge.
Possetitjel schrieb: >> Der Standard unterscheidet zwischen >> - specified ("portabel") >> - implementation-defined ("native") >> - undefined ("verboten") > > Eine bestimmte Sprachkonstruktion fällt aber immer in genau > eine (und immer nur diese eine) Klasse, und ich muss für > jedes Konstrukt WISSEN, welche Klasse das ist. Ja. Das fällt aber unter "kenne deine Werkzeuge", und in C gibt es nicht besonders viele Konstrukte (im Gegensatz zu z.B. C++ oder Java). Du kannst auch nicht Auto fahren, ohne vorher gelernt zu haben, wie man ein Auto bedient. > Ich hatte aber im Sinn, dass man per Direktive im Quelltext > wählen kann, welche genaue Bedeutung dasselbe Sprachkonstrukt > haben soll. Du möchtest also effektiv mehrere Programmiersprachen mit leichten Bedeutungsunterschieden innerhalb einer Datei, zwischen denen du ständig wechseln kannst. Ich sehe darin keinen besonderen Vorteil (und mit Pragmen bekommst du das übrigens auch heute schon - sie sind nur nicht zwischen Compilern portabel). > Das hätte den Vorteil, dass ich nicht den gesamten > Standard im Kopf haben muss, weil nämlich im Quelltext explizit > geschrieben steht, welche Variante jetzt zum Tragen kommt. Und es hat den Nachteil, dass ich mir eine Codezeile "c = a + b" anschaue und es vom Kontext abhängig ist, was sie bedeutet. Ich kann mir also keine isolierten Patches anschauen und sie bewerten, sondern muss im Zweifelsfall die gesamte restliche Codebasis auch im Kopf haben. >> Syntax ist in aller Regel persönlichen Vorlieben geschuldet. > > Ja -- aber nicht nur. > Natürliche Sprachen enthalten alle eine erhebliche Redundanz. Und als Seiteneffekt kannst du Widersprüche ausdrücken: "Dunkel war's, der Mond schien helle, als ein Auto blitzeschnelle langsam um die Ecke fuhr". Wie interpretierst du solche Aussagen eindeutig? Redundanz ist in der Programmierung nicht unbedingt sinnvoll, denn wenn an sich äquivalente Aussagen sich unterscheiden, hast du ein Problem. Das gilt für Copy/Paste ebenso wie für Datenstrukturen mit redundantem Inhalt. > Wo ist diese Redundanz bei "*(++(x*--))"? > Und wo bei "x=(y==z))"? Schlechte Ausdrucksweisen kannst du ebenfalls in jeder Sprache konstruieren: "Ey Alda komma her und krich auffe Fresse isch mach disch Messa" ist grammatisch auch nicht besser als ein Antipattern in der Programmiersprache deiner Wahl. >> In Perl gibt es fast nur syntaktischen Zucker, was die >> Sprache gut zu schreiben und schlecht lesbar macht. In >> Python ist das umgekehrt. Wähle deine Präferenz. > > Tcl. -- Nettes Beispiel :) Mit Tcl werde ich nicht unbedingt warm, da fehlt mir irgendwie Syntax. Ich habe mich damit aber auch nicht weiter befasst, als ich unbedingt musste (= Xilinx). >> Ich wüsste gerne, was genau dein Problem mit C ist, > > Hmm. Ich möchte die Portabilität von C ohne die Macken von > C. Gewisse Einbußen in der Performance wären akzeptabel. Du willst also die Vorteile von C, ohne den Preis zu bezahlen. Ich hätte auch gern einiges, ohne dafür bezahlen zu müssen. > Die ganze Esoterik der L-Values, die dreizehn Vorrangebenen > für Operatoren, die kranke Syntax sind nicht akzeptabel. Für dich nicht akzeptabel. Ich bin z.B. im Gegensatz zu dir bereit, diesen Preis für die Vorteile von C zu zahlen. Du bezahlst halt woanders dafür. Sei es, dass die Programmiersprache deiner Wahl deine Zielarchitektur nicht (oder nur schlecht) unterstützt, du dich in Abhängigkeit zu bestimmten Herstellern begibst, oder oder oder. Es gibt halt nicht alles. C ist vorhanden, mit seinen Stärken und Schwächen, und Alternativen sind auch vorhanden, mit ihren Stärken und Schwächen. Die Lösung deiner Wahl musst du selbst finden oder entwickeln. > Ich bin nur allergisch auf C-Apologeten und C-Missionare. Es gibt offensichtlich genug Programmierer auf diesem Planeten, bei denen die Stärken von C die Schwächen von C hinreichend ausgleichen. > Ich kann durchaus nachvollziehen, warum Brian Kernighan und > Dennis Ritchie die eine oder andere Entscheidung genau SO und > nicht anders getroffen haben. > Ich verstehe nur nicht, warum wir das heute -- 45 Jahre später -- > immer noch genauso machen müssen. Weil sich bestimmte Entscheidungen als gut bewährt haben, und viele schlechte Entscheidungen nicht so schlecht waren, als dass man sie nicht hätte reparieren können oder die guten Entscheidungen gleich mit wegwerfen. Vergleiche mal antiken C-Code mit halbwegs modernem C-Code. Da liegen Welten zwischen. Wir machen das bei weitem nicht mehr genauso wie K&R in den 70ern. Zum Glück. > Schließlich kommt auch niemand auf die Idee, seinen Ruhmkorffschen > Apparat in Funktion zu setzen, wenn er abends sein Zimmer erhellen > möchte :) Wir schicken immernoch Strom durch einen Draht, um ihn zum Glühen zu bringen, um das Zimmer zu erhellen. Wir produzieren immernoch Explosionen in einem Stahlkasten, um uns zügig fortzubewegen. Wir benutzen immernoch "make", um Software zu bauen.
Carl D. schrieb: > Wilhelm lass es einfach. Dieser Thread ist nur noch dazu da, alt > eingesessene "Wahrheiten" vorzutragen. Nutz deine Zeit für spannende > neue Dinge. Vermutlich hast Du Recht :-( In diesem Forum ist es leider doch sehr verbreitet, wenn einem die Argumente ausgehen, sich auf die persönliche Ebene zu begeben, und dann dort irgendwelche abstrusen Vermutungen über die Persönlichkeit der anderen Teilnehmer anzustellen.
Wilhelm M. schrieb: > Carl D. schrieb: >> Wilhelm lass es einfach. Dieser Thread ist nur noch dazu da, alt >> eingesessene "Wahrheiten" vorzutragen. Nutz deine Zeit für spannende >> neue Dinge. > > Vermutlich hast Du Recht :-( > > In diesem Forum ist es leider doch sehr verbreitet, wenn einem die > Argumente ausgehen, sich auf die persönliche Ebene zu begeben, und dann > dort irgendwelche abstrusen Vermutungen über die Persönlichkeit der > anderen Teilnehmer anzustellen. Besonder lustig: "ich verstehe die Sprache nicht, aber hab schon viel (von meinesgleichen) gehört, daß sie besch...en ist". Dann steht da was von "C-Missionaren". Niemand zwingt jemandem, der lieber Pascal schreibt, C auf. Aber der Pascal-Fan muß dann sein Problem "Pascal430" sebst lösen. Ursprungsthema "0-Pointer in C", Nun nur noch "deshalb ist alles, was ich versteh, das Beste". Aber man kennt ja im Lauf der Zeit die Protagonisten.
Wilhelm M. schrieb: > In diesem Forum ist es leider doch sehr verbreitet, wenn einem die > Argumente ausgehen So wie Dir. Ich nannte Dir einige Punkte, und Du gehst lieber auf nichts ein. Wenn Du Dir Dein C++-Getrolle künftig mal sparst, werde ich es nicht vermissen.
Theoretisch könntet ihr euch in Grabenkämpfen zerfleischen, bis nur einer übrig bleibt, und der behält dann automatisch und widerspruchslos recht. Aber in der Realität, wird es immer abweichende Meinungen, Anforderungen und Vorlieben geben.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.