Nullpointer-Frage

Gast #3001227
Lesenswert?

Hallo,

folgendes hab ich im Netz heute gelesen:
1
Laut Sprachdefinition wird ein integraler konstanter Ausdruck mit dem Wert 
2
0 zu einem Null-Zeiger, wenn er einem Zeiger zugewiesen oder auf 
3
Gleichheit mit einem Zeiger verglichen wird (Äquivalenzvergleich). Die 
4
Umgebung (in aller Regel wohl die Übersetzungsumgebung) muß in einem 
5
solchen Fall feststellen, dass ein Null-Zeiger benötigt wird und einen 
6
Wert für den entsprechenden Typ eintragen. Deshalb sind die folgenden 
7
Code-Fragmente einwandfrei:
8

9
      char *z = 0;
10
      if (z != 0)

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
Moderator Persönliche Seite #3001232
Lesenswert?

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.
Gast #3001237
Lesenswert?

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).
Gast #3002773
Lesenswert?

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.
Gast #3002830
Lesenswert?

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.
#3002864
Lesenswert?

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.
#3002896
Lesenswert?

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
void foo( char* str )
2
{
3
  ...
4
}
5

6
void foo( double val )
7
{
8
  ...
9
}
10

11
int main()
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
int main()
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.
#3002909
Lesenswert?

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.
#3002940
Lesenswert?

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 :-)
#3002947
Lesenswert?

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)
Gast #3002948
Lesenswert?

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.
#3003065
Lesenswert?

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.
Moderator Persönliche Seite #3003099
Lesenswert?

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.
#3003176
Lesenswert?

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.
#3003234
Lesenswert?

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.
#3003236
Lesenswert?

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.
Gast #3003261
Lesenswert?

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.
Gast #3004116
Lesenswert?

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.
Persönliche Seite #3004122
Lesenswert?

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.
Gast #3004160
Lesenswert?

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.
Gast #3004169
Lesenswert?

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)
#3004180
Lesenswert?

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.
#3004190
Lesenswert?

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.
#3004192
Lesenswert?

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.
Gast #3004200
Lesenswert?

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...
#3004304
Lesenswert?

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.
#3004536
Lesenswert?

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.
Persönliche Seite #3005058
Lesenswert?

Karl Heinz Buchegger schrieb:

> * was hab ich noch vergessen?

Funktionen ohne Prototyp, register, auto, Trigraphen, Duff's device, ...
1
send (to, from, count)
2
register short *to, *from;
3
register count;
4
{
5
        register n = (count + 7) / 8;
6
        switch(count % 8) {
7
        case 0: do {    *to = *from++;
8
        case 7:         *to = *from++;
9
        case 6:         *to = *from++;
10
        case 5:         *to = *from++;
11
        case 4:         *to = *from++;
12
        case 3:         *to = *from++;
13
        case 2:         *to = *from++;
14
        case 1:         *to = *from++;
15
                } while(--n > 0);
16
        }
17
}
(Firma: JDCC) #3008352
Lesenswert?

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 ;)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren