Allerdings hab ich schon öfter folgende Konstrukte in Quellcodes
gesehen:
1
#define NULL_PTR ((void *)0)
Bedeutet das, NULL_PTR ist hier garkein Nullpointer im C-Sinne?
Sondern ein Zeiger auf die Adresse 0x00?
Weiter: wenn konsequent diese Definition verwendet wird sollte ja nichts
passieren.
Kommen allerdings Bibliotheksfunktionen ins Spiel die einen "echten"
Nullpointer zurückgeben wirds aber kritisch, oder?
Grüße,
lex
lex schrieb:> Bedeutet das, NULL_PTR ist hier garkein Nullpointer im C-Sinne?> Sondern ein Zeiger auf die Adresse 0x00?
Ja, das bedeutet es.
> Kommen allerdings Bibliotheksfunktionen ins Spiel die einen "echten"> Nullpointer zurückgeben wirds aber kritisch, oder?
Sagen wir mal so: in allen praktisch relevanten Fällen auf heutigen
Maschinen nicht, da der Nullzeiger wirklich auch der Zahl 0
entspricht. Ein standardgerechtes Programm sollte aber nicht
versuchen, einen Nullzeiger selbst zu definieren, sondern entweder
wirklich auf 0 vergleichen (dann muss sich der Compiler oder die
Bibliothek ggf. um eine Umwandlung des Bitmusters kümmern, falls eine
exotische Zielmaschine sowas benötigt), oder die Konstante NULL
benutzen, die bspw. von <stdlib.h> oder <stdio.h> zur Verfügung
gestellt werden muss.
Jörg Wunsch schrieb:> lex schrieb:>>> Bedeutet das, NULL_PTR ist hier garkein Nullpointer im C-Sinne?>> Sondern ein Zeiger auf die Adresse 0x00?>> Ja, das bedeutet es.
Ne, tuts nicht...
'Adresse' ist im C-Umfeld ein ziemlich gefährliches Wort. Man sollte
unbedingt trennen zwischen den Adressen innerhalb von C und den
Adressen, die auf der zugrundeliegenden Maschine benutzt werden. Das ist
exakt das, was Jörg mit den Bitmustern meint.
Aber in diesem Fall ist sogar ausdrücklich spezifiziert, dass '(void*)0'
effektiv den Null-Zeiger liefert (ISO/IEC9899:1999 TC2, §6.3.2.3 Abs.
3).
Jörg Wunsch schrieb:>> Bedeutet das, NULL_PTR ist hier garkein Nullpointer im C-Sinne?
Nein.
>> Sondern ein Zeiger auf die Adresse 0x00?
Nein.
> Ja, das bedeutet es.
Nein!
http://c-faq.com/null/index.html beantwortet vermutlich alle Fragen.
Da bin ich beim AVR 'mal auf die Nase gefallen. Ich hatte Zeiger auf
Werte im EEPROM diese und - vorsichtig wie ich bin - vor Benutzung auf
NULL getestet. Nur fängt der Adressbereich für EEPROM halt bei 0 an...
Detlev T. schrieb:> Da bin ich beim AVR 'mal auf die Nase gefallen. Ich hatte Zeiger auf> Werte im EEPROM diese und - vorsichtig wie ich bin - vor Benutzung auf> NULL getestet. Nur fängt der Adressbereich für EEPROM halt bei 0 an...
Das ist egal, C kennt keinen Adressbereich. Genau aus diesem Grund ist
'(void*)0' (also NULL) nicht auch identisch mit Adresse 0.
Sven P. schrieb:>> Da bin ich beim AVR 'mal auf die Nase gefallen. Ich hatte Zeiger auf>> Werte im EEPROM diese und - vorsichtig wie ich bin - vor Benutzung auf>> NULL getestet. Nur fängt der Adressbereich für EEPROM halt bei 0 an...>> Das ist egal, C kennt keinen Adressbereich. Genau aus diesem Grund ist> '(void*)0' (also NULL) nicht auch identisch mit Adresse 0.
Was? Es wird doch der gleiche Assembler/Maschinen-Code erzeugt, wie soll
dann die Zielhardware nachher den Unterschied erkennen?
Beispiel:
1
char*myPtr=(char*)0;
2
if(myPtr==((char*)0))
erzeugt doch den gleichen Assembler/Maschinen-Code wie
1
char*myPtr=(void*)0;
2
if(myPtr==((void*)0))
"myPtr" speichert doch nur einen Wert (den man als Speicheradresse
interpretieren kann), aber nicht eine Qualifizierungsinformation, ob
dieser Wert als char* oder void* übergeben wurde.
> Das ist egal, C kennt keinen Adressbereich. Genau aus diesem Grund ist> '(void*)0' (also NULL) nicht auch identisch mit Adresse 0.
???
Sondern?
Wie willst Du einen void-Zeiger auf die Adresse 0L von NULL
unterscheiden?
Sven P. schrieb:> Das ist egal, C kennt keinen Adressbereich. Genau aus diesem Grund ist> '(void*)0' (also NULL) nicht auch identisch mit Adresse 0.
Konzeptionell.
Als Bitmuster allerdings auf einem AVR letzten Endes schon.
Und genau da liegt auch das Problem mit dieser ganze
Null-Pointer-Konstant Idee. Als Idee nicht schlecht, aber in der Praxis
bringts nix, denn irgendeinen Wert wird man immer als die
Null-Pointer-Konstante vereinbaren, der mit der für die spezielle CPU
typischen Pointergröße prinzipiell darstellbar ist. Und damit hat man
auch immer das Problem, dass dieser Wert in der Praxis regulär vorkommen
könnte. Die Idee, dass der Wert der Null-Pointer-Konstante dergestalt
ist, dass er nicht als regulärer Pointerwert auf dieser speziellen
Hardware nicht auch vorkommen kann, ist zwar nett gedacht, in der Praxis
aber nicht ohne zusätzliche Hilfsmittel (wie zb 1 Byte mehr als die
normale Adressierung auf dieser Maschine verlangt) durchführbar. Das der
Adresswert 0 für die Null-Pointer-Konstante gut funktioniert, ist mehr
der Tatsache geschuldet, dass in der überwiegenden Mehrzahl der Fälle
die Speicheradresse 0 vom Runtime-System sowieso nicht benutzbar ist
(weil da zb das Betriebssystem irgendwelche Werte liegen hat und der
Memory Allokierer diese Adresse niemals liefern wird) als das es der
Tatsache geschuldet ist, dass die Idee hinter dieser
Null-Pointer-Konstante so genial wäre. Hier ist man IMHO weit über das
Ziel hinausgeschossen, ohne tatsächlich etwas zu erreichen.
Karl Heinz Buchegger schrieb:> Null-Pointer-Konstant Idee. Als Idee nicht schlecht
Muss mich korrigieren.
Das ist noch nicht mal als Idee besonders gut.
Wobei Stroustrup die Idee in C++ IMHO noch weiter vermurkst hat.
In C ist wenigstens ein
#define NULL ((void*)0)
zugelassen. Wohlgemerkt: zugelassen. D.h. das ist nichts womit ich als
Programmierer rechnen kann.
In C++ ist es noch nicht mal das. Was dann zu so seltsamen Blüten
treibt, wie diese hier
1
voidfoo(char*str)
2
{
3
...
4
}
5
6
voidfoo(doubleval)
7
{
8
...
9
}
10
11
intmain()
12
{
13
foo(NULL);
14
}
Preisfrage: welche Funktion wird aufgerufen?
Antwort: die Version, die das double Argument nimmt. Und dabei hab doch
extra wunderschön NULL benutzt um anzudeuten, dass ich hier einen
Pointer-Kontext habe. Entschärfen lässt sich das ganze nur, indem ich
selbst die vermeintliche Null-Pointer-Konstante explizit nochmals in
einen Pointer caste
1
intmain()
2
{
3
foo((char*)NULL);
4
}
Sinnig ist das nicht gerade.
Und das bei einer Sprache, die eigentlich die schlimmsten C Fallstricke
'ausmerzen' wollte. Denn auch in C kann mich dieses Problem beißen: bei
variadischen Funktionen. Aber die sind, abgesehen von printf, eher
selten.
Karl Heinz Buchegger schrieb:> In C++ ist es noch nicht mal das. Was dann zu so seltsamen Blüten> treibt, wie diese hier
gibt es aus dem Grund nicht in C++ das nullptr?
Peter II schrieb:> Karl Heinz Buchegger schrieb:>> In C++ ist es noch nicht mal das. Was dann zu so seltsamen Blüten>> treibt, wie diese hier>> gibt es aus dem Grund nicht in C++ das nullptr?
Ja. In C++09.
Also seit rund 4 Jahren :-)
Nicht schlecht für ein Problem, welches in 30 Jahren für unzählige
schlaflose Nächte verantwortlich war.
Alles was Stroustrup 1979 hätte tun müssen, wäre zu definierten, dass in
C++ NULL immer und überall als
#define ((void*)0)
zu definieren ist und das Problem wäre keines mehr gewesen.
>Preisfrage: welche Funktion wird aufgerufen?
Lässt sowas der Compiler zu? Zwei identische Funktionen bzw.
Funktionsnamen?
Kommt da nicht sowas wie "redefinition of function..."
??
Matthias Lipinsky schrieb:> Kommt da nicht sowas wie "redefinition of function..."
nein nicht bei C++ das sind normale überladungen mit anderer signatur.
Matthias Lipinsky schrieb:>>Preisfrage: welche Funktion wird aufgerufen?>> Lässt sowas der Compiler zu? Zwei identische Funktionen bzw.> Funktionsnamen?
C++
C++ hat einige Altlasten von C geerbt. Und in vielen Fällen tatsächliche
Verbesserung gebracht.
Aber hier hat BS IMHO danebengehauen.
Ich teile seine Abneigung für Makros in C++. Aber die Verwendung von
NULL dadurch einzudämmen (weil es ein Makro ist, igitt), dass man
if( ptr == 0 )
möglichst ohne Cast eintippbar macht, war der falsche Weg. Denn
ironischerweise musste er in die Sprachdefinition hier eine Ausnahme für
Pointeroperationen in denen das Integer-Literal 0 vorkommt, einführen,
damit das überhaupt syntaktisch korrekt wird :-)
Matthias Lipinsky schrieb:>>nein nicht bei C++>> Ah ok.>>>>das sind normale überladungen mit anderer signatur.>> Es gilt dann wohl immer die letzte Definition?
No.
Es gilt die Funktion, deren Signatur am besten zu den Datentypen der
Argumente an der Aufrufstelle passt (kurz zusammengefasst. Das ganze
Thema ist bei Klassenhierarchien etwas komplexer - Stichwort:
König-Lookup - aber im Endeffekt läuft es darauf hinaus, dass aus einer
Menge von Kandidaten diejenige Funktion ausgewählt wird, bei der am
wenigsten Konversionen der Argumentdatentypen des Aufrufes notwendig
sind)
Bronco schrieb:> Sven P. schrieb:>>> Da bin ich beim AVR 'mal auf die Nase gefallen. Ich hatte Zeiger auf>>> Werte im EEPROM diese und - vorsichtig wie ich bin - vor Benutzung auf>>> NULL getestet. Nur fängt der Adressbereich für EEPROM halt bei 0 an...>>>> Das ist egal, C kennt keinen Adressbereich. Genau aus diesem Grund ist>> '(void*)0' (also NULL) nicht auch identisch mit Adresse 0.>> Was? Es wird doch der gleiche Assembler/Maschinen-Code erzeugt,
Nein, eben nicht.
Ein Zeiger auf NULL, also etwa '(void*)0' ist immer verschieden von
allen anderen gültigen Zeigern. Auch auf Maschinen und Prozessoren, bei
denen der Speicher ab '0' gezählt wird.
> Beispiel:>
1
>char*myPtr=(char*)0;
2
>if(myPtr==((char*)0))
3
>
> erzeugt doch den gleichen Assembler/Maschinen-Code wie>
1
>char*myPtr=(void*)0;
2
>if(myPtr==((void*)0))
3
>
Richtig und falsch. Es erzeugt hier denselben Maschinencode, weil ein
Zeiger auf 'void' dieselbe Darstellung wie ein Zeuger auf 'char' hat
(ISO/IEC9899:1999TC2 §6.2.5p26). Das Beispiel ist allerdings ungünstig
gewählt.
Ich wähle mal ein günstigeres:
1
double*dp=(double*)0;
2
if(dp==(void*)0)
3
4
/* und */
5
char*cp=(char*)0;
6
if(cp==(void*)0)
Also zwei verschiedene Zeigertypen und das magische NULL.
Daraus wird nicht zwangsläufig derselbe Maschinencode. Aus mehreren
Gründen. Es ist einerseits in C nicht erlaubt, verschiedene Zeigertypen
miteinander zu vergleichen. Lediglich Zeiger auf kompatible Typen (...)
miteinander sowie Vergleiche mit dem void-Zeiger sind zulässig.
Außerdem müssen verschiedene Zeigertypen noch nichtmal gleich groß im
Speicher abgelegt werden. Die könnte ja beispielsweise in total
verschiedene Speicher zeigen.
Schließlich könnte genau das von dir beschriebene Problem eintreten: Die
Speicherstelle '0' ist nutzbar.
> "myPtr" speichert doch nur einen Wert (den man als Speicheradresse> interpretieren kann),
Richtig. Aber den interpretierst nicht du, sondern der Compiler. Wenn er
möchte, könnte er die Zuordnung zwischen Wert des Zeigers und
Speicherstelle im RAM auch rückwärts festlegen. Oder einfach zufällig,
wenn er sich merkt, was wohin landete.
Matthias Lipinsky schrieb:>>das sind normale überladungen mit anderer signatur.>> Es gilt dann wohl immer die letzte Definition?
Nein, die die "passt".
1
voidprint(constchar*str);
2
voidprint(intnum);
Mit print("Hallo") wird die erste Funktion aufgerufen, mit print(42) die
zweite.
Karl Heinz Buchegger schrieb:> In C ist wenigstens ein> #define NULL ((void*)0)> zugelassen. Wohlgemerkt: zugelassen. D.h. das ist nichts womit ich als> Programmierer rechnen kann.
Auf was kann man sich denn hier nicht verlassen?
Karl Heinz Buchegger schrieb:> Preisfrage: welche Funktion wird aufgerufen?
Garkeine, der Aufruf mit '0' als Argument ist nicht eindeutig und muss
zum Compiler-Fehler führen...
Sven P. schrieb:> Karl Heinz Buchegger schrieb:>> Preisfrage: welche Funktion wird aufgerufen?>> Garkeine, der Aufruf mit '0' als Argument ist nicht eindeutig und muss> zum Compiler-Fehler führen...
OK.
Hab ich nicht bedacht.
Gut. Mach aus dem double einen int und gleiche Frage.
Sven P. schrieb:> Karl Heinz Buchegger schrieb:>> In C ist wenigstens ein>> #define NULL ((void*)0)>> zugelassen. Wohlgemerkt: zugelassen. D.h. das ist nichts womit ich als>> Programmierer rechnen kann.> Auf was kann man sich denn hier nicht verlassen?
variadische Funktionen, die eine ungecastete NULL nicht als Pointer
übernehmen sondern als int.
Ist sizeof(int) != sizeof(void*), dann hast du Ärger.
Karl Heinz Buchegger schrieb:> Aber die Verwendung von> NULL dadurch einzudämmen (weil es ein Makro ist, igitt), dass man>> if( ptr == 0 )>> möglichst ohne Cast eintippbar macht, war der falsche Weg.
Ja, er hätte es ja in der Hand gehabt, NULL als reserviertes Wort
einzuführen. Dann muss man das nicht als Makro auflösen, sondern
der Compiler bildet es direkt in seinen Syntaxbaum ab.
Sven P. schrieb:> Ein Zeiger auf NULL, also etwa '(void*)0' ist immer verschieden von> allen anderen gültigen Zeigern. Auch auf Maschinen und Prozessoren, bei> denen der Speicher ab '0' gezählt wird.>
Das läuft jetzt irgendwie auf die m.E. sehr philosophische Diskussion
hinaus, ob dasselbe etwas anderes ist, wenn man es nur anders nennt.
In meiner Welt ist NULL - wie jeder andere Zeigertyp, der den Wert 0L
hat - ein Zeiger auf die Adresse 0, der sich - solange die Maschine es
zulässt (und viele tun das) - dereferenzieren - mit dem sich also
"arbeiten" - läßt.
Daß man Zeiger mit diesem Wert (der selten genug tatsächlich benötigt
wird) dazu benutzen kann, um bestimmte (Sonder-/Fehler-) Situationen zu
kennzeichnen, steht dem keinesfalls entgegen, finde ich.Genausogut hätte
man auch MAXINT verwenden können, aber die Erfinder fanden 0L aus
irgendwelchen Gründen halt praktischer.
Markus F. schrieb:> Genausogut hätte> man auch MAXINT verwenden können, aber die Erfinder fanden 0L aus> irgendwelchen Gründen halt praktischer.
Der Grund ist sehr einfach.
Weil man Pointer dann in einem boolschen Kontext benutzen kann, ohne
irgendwelche Sonderfälle, was wiederrum sehr praktisch beim Abfragen auf
gültig/ungültig ist.
if( ptr )
Das ist schon ok.
>> Ein Zeiger auf NULL, also etwa '(void*)0' ist immer verschieden von>> allen anderen gültigen Zeigern. Auch auf Maschinen und Prozessoren, bei>> denen der Speicher ab '0' gezählt wird.>>>> Das läuft jetzt irgendwie auf die m.E. sehr philosophische Diskussion> hinaus, ob dasselbe etwas anderes ist, wenn man es nur anders nennt.
Das seh ich auch so.
Denn in der Praxis ist diese Vorgabe nicht oder nur mit enormen
Resourcenverbrauch durchführbar. Das ist wie ein spezieller Wert für
int, der von allen mit int darstellbaren Werten verschieden sein soll.
In der Praxis nicht machbar.
Jörg Wunsch schrieb:> Karl Heinz Buchegger schrieb:>> Aber die Verwendung von>> NULL dadurch einzudämmen (weil es ein Makro ist, igitt), dass man>>>> if( ptr == 0 )>>>> möglichst ohne Cast eintippbar macht, war der falsche Weg.>> Ja, er hätte es ja in der Hand gehabt, NULL als reserviertes Wort> einzuführen. Dann muss man das nicht als Makro auflösen, sondern> der Compiler bildet es direkt in seinen Syntaxbaum ab.
Und genau so ist es dann ja letztenedes auch gekommen :-)
Nur 30 Jahre und Milliarden von Lines of Code zu spät.
Markus F. schrieb:> In meiner Welt ist NULL - wie jeder andere Zeigertyp, der den Wert 0L> hat - ein Zeiger auf die Adresse 0, der sich - solange die Maschine es> zulässt (und viele tun das) - dereferenzieren - mit dem sich also> "arbeiten" - läßt.
Naja, das ist ja schon auf deinem PC nicht mehr der Fall. Da steckt noch
die MMU dazwischen.
Die Implementierung des NULL ist natürlich am simpelsten, wenn man den
auch tatsächlich auf Speicherstelle '0' setzt. Das vereinfacht ja qausi
schon das Assembly, weil man nur auf '0' testen muss. Aber es ist halt
nichts, auf das man sich verlassen kann.
Solche Diskussionen haben ganz stark akademischen Charakter, da stimme
ich aber zweifellos zu. Allerdings sind sie manchmal notwendig, um
subtile Fehler zu begreifen.
jack schrieb:> Und wie würde ich bei meinem Atmel zB auf die Adresse 0 zugreifen?>> Char *ptr = 0;> DoSomething(*ptr);>> So?
Ja.
Bei den AVR Compilern hat die Null-Pointer-Konstante auch tatsächlich
alle Bits auf 0.
Karl Heinz Buchegger schrieb:> Ja.
Danke.
Mit der Antwort wär ich glücklich gewesen, aber...
> Bei den AVR Compilern hat die Null-Pointer-Konstante auch tatsächlich> alle Bits auf 0.
...verwirrt mich jetzt.
Hat das was mit meiner Frage zu tun?
Nachdem was ich hier gelesen habe ist:
void *ptr = 0; ein NULL-Pointer
char *ptr = 0; ein Zeiger auf die bei AVRs gültige Adresse 0x00
Dennoch sind doch im zweiten Fall auch alle Bits auf 0, richtig?
Nur durch die Deklaration mit void* wird Ersteres vom Compiler als
NULL-Pointer interpretiert. Die interne Darstellung müsste ja gleich
sein bzw. keine Rolle spielen.
jack schrieb:> ein Zeiger auf die bei AVRs gültige Adresse 0x00
Im Prinzip ja, allerdings liegt dort das Register R0, es sit also
vermutlich keine gute Idee überhaupt dorthin direkt zu schreiben auch
wenn es möglich wäre, ich denke nicht das der Compiler erkennt das du
ihm gerade eines seiner Register überbretzelst.
Und genau das ist doch der Punkt: Ich arbeite doch (hoffentlich) mit vom
Compiler verwalteten Variablen, wenn nicht (wie beim EEPROM der oben
angesprochen wurde) kann ich mich auch nicht auf die "Null-Pointer"
Konvention verlassen oder muss mir was anderes ausdenken.
jack schrieb:> void *ptr = 0; ein NULL-Pointer> char *ptr = 0; ein Zeiger auf die bei AVRs gültige Adresse 0x00
Beim AVR GCC kann man das NULL-Pointer-Konzept nicht so einfach
realisieren, da der Compiler nicht zwischen gültiger Adresse 0 und
NULL-Pointer unterscheidet.
Der Compiler müßte dazu zu jedem Pointer zusätzliche Informationen
speichern (was es z.B. beim 8051 gibt, aber aus ganz anderen Gründen).
Natürlich kannst Du für Deine Anwendung definieren, daß die Zahl 0 als
Erkennung von ungültigem Inhalt verwendet wird, wenn Du Dir sicher bist,
daß Du niemals auf die Adresse 0 zugreifen mußt.
Wenn Du z.B. Objekte im RAM behandelst, wirst Du niemals Adresse 0
verwenden, da dort die Register liegen.
Bei den allermeisten Prozessoren liegt an der realen Adresse Null
irgendein prozessorspezifischer Kram.
Sei es Register, Zeropage, ROM, Resetadressen, ...
Also Sachen, die man in "normalen" Programmen gar nicht braucht.
Und bei den anderen Programmen kann über den NULL-Pointer auch darauf
zugreifen (wenn die Rechte dafür vorhanden sind)
jack schrieb:> Karl Heinz Buchegger schrieb:>> Ja.> Danke.>> Mit der Antwort wär ich glücklich gewesen, aber...>> Bei den AVR Compilern hat die Null-Pointer-Konstante auch tatsächlich>> alle Bits auf 0.> ...verwirrt mich jetzt.>> Hat das was mit meiner Frage zu tun?> Nachdem was ich hier gelesen habe ist:> void *ptr = 0; ein NULL-Pointer> char *ptr = 0; ein Zeiger auf die bei AVRs gültige Adresse 0x00>> Dennoch sind doch im zweiten Fall auch alle Bits auf 0, richtig?
genau.
> Nur durch die Deklaration mit void* wird Ersteres vom Compiler als> NULL-Pointer interpretiert.
:-)
Um die Verwirrung aufzulösen.
Der C-Standard sagt nichts dazu, welchen konkreten Typ der Pointer haben
muss. Ob der ein void* oder ein char* ist, spielt überhaupt keine Rolle.
Es ist die reine Zuweisung von 0 an einen Pointer, die den Compiler dazu
veranlasst, die 0 (!) als Null-Pointer-Konstante anzusehen und
gegebenfalls diese 0 durch ein anderes Bitmuster auszutauschen. Die 0,
und ihre Verwendung in einem Pointer-Kontext ist der springende Punkt!
Aber auf dem AVR hat die Null-Pointer-Konstante ebenfalls den Zahlenwert
0. So wie auf den meisten Systemen. Ich kenne eigentlich kein System,
bei dem das anders wäre.
Karl Heinz Buchegger schrieb:> Wobei Stroustrup die Idee in C++ IMHO noch weiter vermurkst hat.
Das dürfte damit zusammenhängen, dass C++ keine cast-freie Konvertierung
von void* nach sonstwas* zulässt. Das würde nämlich allzu leicht das
ganze Typenkonzept von Klassen aushebeln, insbesondere bei multiple
inheritance (da wird ggf. die Adresse umgerechnet).
Richtiger wäre allerdings ein nullptr gewesen.
Karl Heinz Buchegger schrieb:> Aber auf dem AVR hat die Null-Pointer-Konstante ebenfalls den Zahlenwert> 0. So wie auf den meisten Systemen. Ich kenne eigentlich kein System,> bei dem das anders wäre.
Heute nicht mehr. Gab es aber. Bei den Transputern war der Adressbereich
mit Vorzeichen realisiert, beim 16-Bitter T212 also -0x8000...+0x7FFF.
Die 0 folglich mitten drin.
Karl Heinz Buchegger schrieb:> Es ist die reine Zuweisung von 0 an einen Pointer, die den Compiler dazu> veranlasst, die 0 (!) als Null-Pointer-Konstante anzusehen und> gegebenfalls diese 0 durch ein anderes Bitmuster auszutauschen.
JA JA JA RICHTIG! :-)
Hach was war das alles so einfach, als man sich über sowas noch keine
Gedanken gemacht hat...
A. K. schrieb:> Karl Heinz Buchegger schrieb:>> Aber auf dem AVR hat die Null-Pointer-Konstante ebenfalls den Zahlenwert>> 0. So wie auf den meisten Systemen. Ich kenne eigentlich kein System,>> bei dem das anders wäre.>> Heute nicht mehr. Gab es aber. Bei den Transputern war der Adressbereich> mit Vorzeichen realisiert, beim 16-Bitter T212 also -0x8000...+0x7FFF.> Die 0 folglich mitten drin.
Sachen gibts :-)
Im Ernst.
Im C-Standard sind einige Anachronsimen enthalten, die früher mal
relevant waren, aber schon seit einiger Zeit komplett irrelevant sind
* Zeichensatz
Die Zugeständnisse an EBCDIC (denn genau das waren sie letzten Endes)
sind längst überholt. EBCID hat heute m.W. keine Bedeutung mehr.
Auch IBM ist bei seinen Mainframes (bauen die überhaupt noch welche?)
längst auf ASCII gewechselt.
* 2-er Komplement Arithmetik
Ok, da mag es heute noch Ausnahmen geben, könnte sein. Ich denke
allerdings nicht. Ich denke, es wäre kein Beinbruch, wenn man
auch signed Arithmetik mit 2-er Kompl. Arithmetik im Hinterkopf
aus seinem undefined Status holt. 1-er Komplement und sonstige
Variationen sind längst tot, hat sich alles nicht wirklich
bewährt.
* Floating Point
Die ganze Welt verwendet mitlerweile die IEEE Funktionalität.
OK, ältere Vaxen mit ihrem eigenen Floating Point Format haben
dann das nachsehen. Würde mich allerdings wundern, wenn da noch
groß Aufwand in die Neuentwicklung eines C-Compilers gesteckt wird.
* und eben die Sache mit der 0-Pointer-Konstanten
* was hab ich noch vergessen?
Denn die Sache ist doch die. Berücksichtigt man beim Programmieren all
diese Dinge, dann hat man einen riesen Aufwand. Es würde mich sehr
wundern, wenn man mehr als ein paar Prozentpunkte der real existierenden
Programme nehmen könnte und auf eine Maschine mit einer derartigen
Besonderheit laufen könnte, ohne dass es zu Problemen kommt. D.h. de
facto hat sich die Computer-Industrie längst in all diesen Bereichen auf
Standards eingeschossen. Die Zeit des ausprobierens ist längst vorbei.
Die Flexibilität, die im C-Standard notwendig war um das alles unter
einen Hut zu bringen, braucht man heutzutage gar nicht mehr. Aber ich
weiß auch, dass die ISO-Gremien da sehr konservativ sind. Eher kann man
die 10 Gebote ändern, als das etwas aus dem Standard rausfliegt, was da
bereits drinn steht.
Karl Heinz Buchegger schrieb:> Auch IBM ist bei seinen Mainframes (bauen die überhaupt noch welche?)
Und ob die noch welche bauen: http://www-03.ibm.com/systems/z
Sind zwar rein physisch nicht grösser als deren Highend-RISCs und auch
nicht schneller, aber in Sachen Verfügbarkeit ziemlich Spitze.
> Die ganze Welt verwendet mitlerweile die IEEE Funktionalität.
Sogar besagte Mainframes beherrschen schon ein Weilchen neben IBMs altem
Hex-Fliesskommaformat auch das IEEE-Format.
Karl Heinz Buchegger schrieb:>> Heute nicht mehr. Gab es aber. Bei den Transputern war der Adressbereich>> mit Vorzeichen realisiert, beim 16-Bitter T212 also -0x8000...+0x7FFF.>> Die 0 folglich mitten drin.
Da gab's noch mehr: http://c-faq.com/null/machexamp.html . Überwiegend
obsolet, trotzdem interessant zu wissen, finde ich.
Karl Heinz Buchegger schrieb:> * Zeichensatz> Die Zugeständnisse an EBCDIC (denn genau das waren sie letzten Endes)> sind längst überholt. EBCID hat heute m.W. keine Bedeutung mehr.> Auch IBM ist bei seinen Mainframes (bauen die überhaupt noch welche?)> längst auf ASCII gewechselt.
Ich bekomme recht viele Daten in EBSCDIC, natürlich in irren Varianten
um deutsche Umlaute unterzubringen ... Das gibt's echt noch ;)
>Duff's device
Das ist doch auch so eine C-Eigenheit. Oder welche Sprache lässt es
sonst noch zu, die CASE-Anweisung und die WHILE-Schleife gegenseitg so
zu verschachteln...