Hallo, ich möchte einen Zeiger, den ich in main initialisiert habe, einer Funktion übergeben. Leider funktioniert das nicht. Ich bekomme bei der Ausführung des Programms (Visual Studio) immer einen Speicherverletzungs fehler. Kann mir mal bitte jemand weiterhelfen. Auf einem uC funktiniert das auch nicht. Ich stehe gerade voll auf der Leitung.... unsigned char SPI0_ADC(unsigned int *pData, unsigned char cChannel) { if (cChannel == 1) *pData = 0x100; // Access violation :-( else *pData = 0x200; return 0; } int main(int argc, char* argv[]) { unsigned int *pADC = 0; unsigned int iTest; SPI0_ADC(pADC,1); iTest = *pADC; return 0; }
Speicherverletzung, klar!!! Wo zeigt denn der Zeiger hin? Muß man dem nicht vorher eine Adresse zuweisen? Gruß Dietmar
Adresse zuweisen, das sollte der Compiler erledigen. PS: Call by Referenz nützt mir nichts, bzw. ist in meinem Fall sehr unelegant.
Wenn ich das richtig sehe, initialisierst du den Pointer in main eben nicht. Entweder: > unsigned int *pADC = 0; > pADC=(unsigned int*)malloc(sizeof(unsigned int)) oder: > unsigned int pADC = 0; > [...] > SPI0_ADC(&pADC,1); sollten gehen. Aber ohne Gewähr. Beste Grüße, Bartl
"Adresse zuweisen, das sollte der Compiler erledigen." Nö. Bei Zeigern eben gerade nicht. "unsigned int *pADC = 0;" Bedeutet: Zeiger hat den Wert "kein Speicher zugewiesen". Alternative: unsigned int wert; unsigned int *pADC = &wert, dann geht's auch ohne Crash.
Hmm. Ist einfacher wenn dir klar ist, was da passiert. Ist nicht so der Knüller, wenn du das bei jeder Messung machst und dabei das free() vergisst ;-). Zudem neige ich bei Controllern dazu, dynamische Speicherverwaltung so weit wir irgend möglich zu vermeiden. Zu schlecht kalkulier- und kontrollierbar.
Noch einfacher ist: int main() { int DerWertVomADC; SPI0_ADC( &DerWertVomADC, 1 ); // .. und hier ganz einfach mit dem Wert weiterarbeiten, // den SSPIO_ADC in DerWertVomADC abgelegt hat
> Adresse zuweisen, das sollte der Compiler erledigen.
Wie kommst du auf das schmale Brett?
Du solltest in main versuchen:
1 | unsigned int pADC; |
2 | // ...
|
3 | SPI0_ADC(&pADC,1); |
> PS: Call by Referenz nützt mir nichts, bzw. ist in meinem Fall > sehr unelegant. Wieso? Das ist doch genau das, was du tust.
>Nö. Bei Zeigern eben gerade nicht. >"unsigned int *pADC = 0;" >Bedeutet: Zeiger hat den Wert "kein Speicher zugewiesen". Das ist falsch, Es bedeutet erstelle einen Zeiger auf einen int Wert mit dem Namen pADC der auf Adresse 0 zeigt. Der Zugriff auf diese Adresse mittels des Zeiger ist illegal/falsch, es sei denn dem Programm gehört der Bereich, unter Windows recht unwahrscheinlich, deshalb der Speicherfehler
> Der Zugriff auf diese Adresse mittels des Zeiger ist illegal/falsch, > es sei denn dem Programm gehört der Bereich, Selbst wenn an der Adresse 0 Speicher liegt, und dieser Speicher auch zugreifbare wäre, ist es trotzdem illegal. Ein Dereferenzieren eines 0-Pointers ist in C immer illegal und führt zu undefiniertem Verhalten. Das ist auch dann so, wenn durch Optimierung die Deferenzierung rausoptimiert wird. Das undefinierte Verhalten bleibt bestehen. Ist in C nicht so ein Thema, kommt in C++ aber immer wieder aufs Tapet, wenn Schlauberger meinen, sie können die Aussage: 'Es kann keine 0-Referenz geben' mit dem Code beantworten: void foo( int& a ) { // hier ist a eine 0-Referenz } int* pI = 0; foo( *pI ); Dieser Code zeigt undefiniertes Verhalten, da der Ausdruck *pI, bei einem Wert von 0 in pI schon illegal ist. Die Bindung der Referenz erfolgt erst danach.
>>"unsigned int *pADC = 0;" >>Bedeutet: Zeiger hat den Wert "kein Speicher zugewiesen". > > Das ist falsch, Nein, ist es nicht. > Es bedeutet erstelle einen Zeiger auf einen int Wert mit dem Namen > pADC der auf Adresse 0 zeigt. Nein. Es wird ein Nullzeiger erstellt. Wie die Bits eines Nullzeigers aussehen, ist implementationsspezifisch. Der Wert muß nicht mal die Adresse einer existierenden Speicherstelle sein (oder überhaupt eine Adresse). Oft ist es ein Zeiger, bei dem alle Bits 0 sind, aber das muß nicht sein. > Der Zugriff auf diese Adresse mittels des Zeiger ist > illegal/falsch, Nach C-Norm formuliert: Das Dereferenzieren eines Nullzeigers führt zu undefiniertem Verhalten.
Mir ist noch kein C System begegnet, in NULL nicht den Wert 0 hatte. Allein schon weil beliebig viele Programmierer 0, NULL und '\0' hoffnungslos durcheinanderbringen. Und zumindest in C++ die Zuweisung von 0 ausdrücklich so definiert ist. Folglich steht unsigned int *pADC = 0; für "pADC ist keine Speicheradresse zugewiesen". In C++ per Definition, in C89 mindestens de fakto. "Es bedeutet erstelle einen Zeiger auf einen int Wert mit dem Namen pADC der auf Adresse 0 zeigt." Hab ich anders in Erinnerung. Bei jedem anderen Wert ist das ohne Cast ein Fehler, nur bei 0 ist es erlaubt. Selbst wenn ein C-System mutig genug ist, intern einen anderen Wert dafür zu verwenden, ist der Compiler gut beraten, die Zuweisung von 0 entsprechend umzurechnen. D.h. selbst wenn der interne Wert für "ungültiger Zeiger" 0xDEADBEEF betragen sollte, sollte ein Compiler aus "p = 0" dann intern "reg = 0xDEADBEEF" daraus machen.
Ok, Danke schön. Also malloc werde ich in einem Controller niemals einsezten. unsigned int iadr = 0; unsigned int *pADC = &iadr; Mit diesen Konstrukt habe ich mein Problem lösen können. Kann ich in der Zeiger deklaration nicht auch meinen Zeiger gleich einen Wert mit übergeben??? unsigned int iadr = 0; unsigned int *pADC = &iadr; *pADC = 200; Das sind schließlich drei Zeilen.
Was willst Du überhaupt machen? > unsigned int iadr = 0; > unsigned int *pADC = &iadr; > *pADC = 200; danach hat die Variable iadr den Wert 200. Ist es das was Du willst?
> Mir ist noch kein C System begegnet, in NULL nicht den Wert 0 hatte. Das heist nicht das es sie nicht gibt :-) > Allein schon weil beliebig viele Programmierer 0, NULL und '\0' > hoffnungslos durcheinanderbringen. Auch das ist kein Problem. In dem Moment, indem der 0-Zeiger auf einem System nicht aus 'alle-bits-0' besteht, muss sich der Compiler drum kuemmern, dass jede Zuweisung von 0, auch dann wenn sie aus einem arithmetischen Ausdruck kommt, zu genau diesem Bitmuster umgesetzt wird. #define NULL (void*)( 2 - 2 ) ist eine gültige Definition für NULL in C ! ( In C++ natuerlich nicht, wegen dem Cast zu void*)
> Kann ich in der Zeiger deklaration nicht auch meinen Zeiger gleich > einen Wert mit übergeben??? Ich denke der springende Punkt in deinem konreten Fall ist: Du brauchst auf seiten des Aufrufers überhaupt keine Pointervariable! die Funktion möchte eine Adresse haben, an der sie das Ergebnis ablegen kann. Na dann gib ihr halt eine Adresse. Zum Beispiel die Adresse einer Variablen: unsigned int ADC; SPI0_ADC( & ADC, 1 ); SPIO_ADC ist glücklich damit, und legt den ermittelten Wert direkt in ADC ab. Mehr willst du doch nicht, oder?
>unsigned int ADC; >SPI0_ADC( & ADC, 1 ); Was ich ja vor zwölf Posts auch schon geschrieben hab'...
Ok an alle die behaupten ein Zeiger auf Adresse 0 sei Compilerspezifisch illegal etc.: Ich behaupte nicht das der übliche test eines Zeiger auf NULL gewöhnlich wirklich mit 0 gemacht wird, aber wenn ich einem Zeiger den Wert 0 zuweise, dann denke ich der Prozessor greift auch auf Adresse 0 zu. Wenn dann Hardwareschutzmechanismen dies verhindern ist eine andere Sache. Oder ist hier jemand der Meinung man könnte tatsächlich nicht in C auf Adresse 0 zugreifen. Wenn ja, wie greift ihr dann in C z.B. in Dos auf die Interrupttabelle zu oder beim AVR im Datenbereich auf Adresse 0 (ok ginge auch ueber R0..)? Oder gibt es da im C Standard sowas, was sagt einen Zugriff auf Adresse 0 ueber Zeiger geht nicht?
War etwas blöd formuliert. NULL ist in den Includes schon öfter als ((void *)0) definiert. Leider. Weil mir schon öfter Programme untergekommen sind, indenen konsequent Unfug der Art char *p: *p = NULL; geschrieben stand. War ne Menge Arbeit das grade zu biegen. Aber ein System, das nicht das Bitmuster 0 verwendet, ist schon mutig. Ich kenne zumindest eine Architektur, in dem die Versuchung da ist. Denn der Adressraum von Inmos Transputern war verrückterweise mit Vorzeichen definiert, d.h. von -0x80000000 bis + 0x7FFFFFFF, und da liegt 0 genau mitten drin. Ok, beim 32-Bitter war das damals egal, denn sowiel Speicher hatte eh niemand. Aber bei 16-Bitter, da wurde es ernst. Müsste echt mal nachsehen wie ich das damals im Compiler realisiert hatte - vielleicht strafe ich meine eigene Aussage oben Lügen und hab es selber anders definiert ;-).
@Wolfram: "aber wenn ich einem Zeiger den Wert 0 zuweise, dann denke ich der Prozessor greift auch auf Adresse 0 zu." Nein, nicht zwingend. Versuch mal, zwischen "Integer-Konstante 0 im Kontext einer Adresse" und "Adresse 0 im Adressraum des Programms" einen Unterschied zu machen. Ist nämlich nicht das gleiche.
> Ok an alle die behaupten ein Zeiger auf Adresse 0 sei > Compilerspezifisch illegal etc.: Es geht nicht um einen Zeiger auf Adresse 0, sondern um einen Nullzeiger. Das sind zwei verschiedene Dinge. Karl Heinz hat das bereits erklärt. > aber wenn ich einem Zeiger den Wert 0 zuweise, dann denke ich der > Prozessor greift auch auf Adresse 0 zu. Kann er, muß er aber nicht. Gerade bei einem Mikrocontroller könnte es durchaus sinnvoll sein, dem Nullzeiger einen anderen Wert zu geben, um nicht das Byte an Adresse 0 zu verschenken. > Oder ist hier jemand der Meinung man könnte tatsächlich nicht in C > auf Adresse 0 zugreifen. Das eine hat mit dem anderen nichts zu tun. Man kann schreiben: int x = 0; void* p = (void*)x; Das ergibt einen Zeiger auf Adresse 0. Im Gegensatz dazu ergibt void* p = 0; einen Nullzeiger. Die Adresse, die er enthält, muß nicht unbedingt 0 sein. > Oder gibt es da im C Standard sowas, was sagt einen Zugriff auf > Adresse 0 ueber Zeiger geht nicht? Die C-Norm sagt überhaupt nichts über die Adresse 0, sondern über den Nullzeiger. Was sie sagt, ist, daß das Dereferenzieren desselben zu undefiniertem Verhalten führt.
>Lies den C Standard Würde ich gerne kostet aber zu viel aber jetzt mal ernsthaft , meiner Meinung nach hat ein Nullzeiger in C den Wert NULL und darf nicht dereferenciert werden. dagegen ein Zeiger den ich 0 zuweise weisst auf die Adresse 0 mit der Meinung stehe ich da auch nicht ganz alleine siehe: http://de.wikipedia.org/wiki/Zeiger_(Informatik) >In Pascal-basierten Sprachen wie Delphi bzw. Object Pascal heißt der >Nullzeiger beispielsweise nil (lateinisch: "nichts" oder Akronym für >"not in list"), in C NULL, und in C++ einfach die Zahl 0 und wir sprachen doch über C Wenn mir jemand einen Link zum C-Standard gibt wo etwas anderes steht. Ich bin immer froh, wenn ich mein Wissen erweitern kann.
Der Zugriff auf Adresse 0 ist nötig und möglich. Z.B. muß man bei 8051-ern mit Bootloader zum Aufruf der API-Funktionen das Register R0 laden, was an der Adresse 0 ist. Zufälliger Weise ist es auch noch ein Pointerregister. Wenn ich also indirekt auf die Adresse 0 zugreife, wird erst R0 mit 0 geladen und dann dessen Inhalt mit dem Wert. Man muß also darauf achten, daß das Laden von R0 der letzte indirekte Zugriff vor dem API-Call ist. deshalb wird auch r1 zuerst geladen und danach R0. Anbei mal das Listing dazu. Peter
"meiner Meinung nach hat ein Nullzeiger in C den Wert NULL und darf nicht dereferenciert werden." Vorsicht Falle. Eine Zeigervariable, der "NULL" oder auch "0" zugewiesen wurde, hat zwar diesen Wert, zeigt aber nicht unbedingt auf die Adresse 0. Wert != Bitmuster, siehe unten. So steht's auch in der Wikipedia: "Der Nullzeiger ist ein Zeiger mit einem speziellen, dafür reservierten Wert (nicht zwingend numerisch 0)". "dagegen ein Zeiger den ich 0 zuweise weisst auf die Adresse 0" Und ab da ist's falsch. Vielleicht hilft dir ein Vergleich mit Fliesskommazahlen. Im Intel'schen 80bit-Format hat die Darstellung der Zahl 0.0 keineswegs das Bitmuster 0000....0000, sondern 000...010...000. Und ebenso muss das Bitmuster des Zeigers "0" keineswegs "0000...0000" (Adresse 0) sein.
"Der Zugriff auf Adresse 0 ist nötig und möglich." @PeDa: Das hat du ein bischen sehr allgemein ausgedrückt. Bloss weil es bei Systemen ohne MMU ein Zugriff auf die Adresse 0 meistens möglich ist, wird da keine Vorschrift draus. Bei AVR geht's auch, mit dem gleichen Ergebnis. Aber das ändert nichts. Ein Beispiel mit Type-Cast ist ungefähr vergleichbar zu einem mathematischen Beweis mit Hilfe einer Division durch 0. "cast" steht für wegwerfen. Damit kannst du beiweisen dass 1==2. Tatsächlich sitzt ein Compilerbauer bei manchen Systemen etwas in der Falle. Es gibt manchmal keine Adresse im Datenadressraum, die nicht irgendwie irgendwann mal verwendet werden könnte. Dann gibt es keinen natürlichen Wert für den "null pointer". Ist in der Praxis nicht ganz so schlimm, da auf offizieller(!) C Ebene keine Möglichkeit besteht, die Adresse eines Registers zu verwenden. Und so stört es nicht, wenn bei 8051 oder AVR der "null pointer" identisch ist mit einem Zeiger auf R0.
Hi Leute, also soweit ich das mal hier überflogen hab, streitet Ihr aneinander vorbei. g Ich hab das so gelernt und begriffen: Ein Pointer/Zeiger wird werwendet um auf eine bestimme Speicheradresse zuzugreifen. Fals hier wieder welche schreien: Es ist Programm/Systemabhänig, ob ich einen eigenen virtuellen Adressbereich zugewiesen bekomme oder auf dem physikalischen Speicher rumwurschtlen kann. Das ich dafür Pointer verwenden kann ist klar, hat aber mit den Pointern selbst nix zu tun. Also weiter, wenn ich also einem Pointer einen Wert X zuweise, dann ist X die Speicheradresse auf die ich zugreife. Nun existiert das Problem, das man auch Pointer benötigt, die noch kein Ziel, also keine Adresse haben, benötigt. (z.B. für dynamische Listen) Damit lege ich einen Pointer fest, der ins Datennirvana zeigt. Eine Maschine und die darauf laufende Software hat nun aber ein Problem, denn wie stellt man mit einem Bitmuster KEINE Adresse dar? Somit wurden spezielle Keywords eingeführt: NIL, NULL. Diese zeigen natürlich auf irgendwelche Adressen, denn wie schon erwähnt gibt es kein Bitmuster für KEINE Adresse. Ein Compiler wird dafür natürlich irgendwelche Adressen nehmen die selten oder im Normalbetrieb nie benötigt werden. (also z.B. 0 oder 0xFFFFF) NIL/NULL sind für den Programmier gedacht um dem Compiler zu sagen hier ist was was ich benötige, aber noch nicht weiß wo... aber halt mal den Platz frei. Somit kann der Compiler prüfen, das der "vergessliche" Nutzer keine Pointer benutzt, denen noch keine richtige Adresse zugewiesen wurden. Deswegen zeigt ein Pointer = 0 auf Adresse 0. (wenn er das nicht macht, würde ich den Compile wechseln...) Und der Compile wird nicht meckern wenn ich diesen Pointer beschreibe. Ein Compiler wird aber wohl meckern wenn ich ein Pointer = NULL beschreibe. (Dieser kann aber durchaus auch auf Adresse 0 zeigen.... muß aber nicht.) Also nochmal zusammenfassend: - Pointer = NULL reservierter Speicherplatz für einen Pointer der noch nirgens hinzeit und wo der Compiler meckern sollte, wenn man ihn benutzt ohne eine gültige Adresse vorher zuzuweisen - Pointer = 0 ein Zeiger der aud Speicheradresse 0 zeigt Grüße und ab ins Wochenende
>> Lies den C Standard > Würde ich gerne kostet aber zu viel Hmm. Früher gab's das mal für $18, aber scheinbar jetzt nicht mehr. > aber jetzt mal ernsthaft , meiner Meinung nach hat ein Nullzeiger > in C den Wert NULL und darf nicht dereferenciert werden. Das stimmt. > dagegen ein Zeiger den ich 0 zuweise weisst auf die Adresse 0 > mit der Meinung stehe ich da auch nicht ganz alleine Bei dem, was du da zitierst, steht nirgends, daß eine Zuweisung von 0 an einen Zeiger zu einem Zeiger auf die Adresse 0 führt. > Wenn mir jemand einen Link zum C-Standard gibt wo etwas anderes > steht. Hier mal ein Ausschnitt: 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. ... 5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.56) ... 55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.17. 56) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.
@Rolf Magnus > int x = 0; > void* p = (void*)x; > Das ergibt einen Zeiger auf Adresse 0. Stimmt, ist auch alles korrekt, Leider hast du dann einen Zeiger auf Adresse 0 mit dem du nichts anfangen kannst, Das dereferenzieren von untypisierten Zeigern ist nicht möglich. > Im Gegensatz dazu ergibt > void* p = 0; > einen Nullzeiger. Die Adresse, die er enthält, > muß nicht unbedingt 0 sein. und genau darüber möchte ich diskutieren, meiner Meinung nach ergibt das in C einen Zeiger auf Adresse 0 aus Sicht des C-Compilers. Ich spreche hier erstmal nicht von physikalischen Adressen. Ein Nullzeiger hat den wert NULL, der Zeiger, nicht der Wert auf den er zeigt. Deshalb ist das auch völliger Unfug: >char *p;*p = NULL; Erstelle eine Zeiger auf eine char und schreibe dorthin wohin der Zeiger zeigt (absolut undefiniert) den Wert NULL Wenn dann kann man einem Zeiger NULL zuweisen und damit ihn zum "NULL Pointer" machen. char *p;p = NULL; so wird ein Nullpointer draus. Sollte das im C-Standard anders definiert sein gebt mir einen Link auf die stelle. Ich ziehe es bis dahin vor das ich in C auch auf Adresse 0 zugreifen kann. ich gehe dann erstmal ins Wochenende und bin am Montag sehr gespannt auf diesen Thread...
"ich gehe dann erstmal ins Wochenende und bin am Montag sehr gespannt auf diesen Thread..." Spielverderber ;-).
@Wolfram: Kann man so sehen. Du baust dir aber mit dieser Terminologie ("Adresse aus Sicht des Compilers") ein eigenes Begriffs- und Koordinatensystem, indem sich niemand ausser du selbst auskennt. Kleine Scherzfrage dazu: char *p = (char *)0; char *q = (char *)1; char *r = (char *)2; was sind jetzt die Werte q - p und r - q in formell korrektem C?
Deine Frage widerspricht sich selbst. In formell korrektem C darf man nämlich Zeigerarithmetik nur mit Zeigern betreiben, die auf Elemente ein- und desselben Arrays (oder ein Element danach) zeigen.
Ok, wieder aus dem Wochenende zurück, >("Adresse aus Sicht des Compilers") Es hat seinen Grund weshalb ich diese Formulierung verwendete, Wenn ich eine Firmware/Bios etc schreibe wird für mein Programm die Adresse 0 wohl her am Anfang des Speicher liegen, wenn ich ein Programm in Dos/Windows/Linux schreibe wird Adresse 0 wohl eher am Anfang des Datensegmentes des Programmes liegen. Es gibt da ja noch eine Schicht im Betriebssystem/hardware die logische in physikalische Adressen umrechnet. Wenn es ganz verquere Architekturen sind wo der Compilerhersteller in der Zwickmühle sitzt die Doku der Hersteller muss ich so oder so lesen. Oder laut zitat: >56) The mapping functions for converting a pointer to an integer or >an integer to a pointer are intended to be consistent with the >addressing structure of the execution environment. Zur Scherzfrage: die Ausdrücke q-p,r-q sind unbestimmt da ein Compiler ein Alignent durchführen könnte, derartiges geht, wie Rolf Magnus schon sagte nur innerhalb eines Arrays. @Rolf Magnus Aus welchem Standard zitierst du da; K&R,C89,C99? nach dem Standard ist die Zuweisung mit integer constant was wird denn das wenn es keine Konstannte ist, wie will der Compiler den dafür sorgen das das zur Laufzeit noch auseinander gehalten wird? Ich ziehe einen sauberen Programmierstil vor und wenn ich einen Nullpointer haben will, dann benutze ich NULL in C. Die nach 56) geforderte Konsistenz würde für mich bedeuten das ein Zugriff auf Adresse 0 im executing environment auch möglich ist. Da ich ihn über eine nicht konstante erzeugen kann muss der Zugriff auf die selbe Adresse auch über eine konstante möglich sein sonst wäre die Konsistenz verletzt. Wahrscheinlich ist das eher eine Diskussion für das C-Sprach-Standard Forum. Die Frage mal anderes gestellt: Ist euch je ein Compiler untergekommen auf bei dem ihr nicht auf Adresse 0 des executing environment zugreifen konntet?
> Ich ziehe einen sauberen Programmierstil vor und wenn ich einen > Nullpointer haben will, dann benutze ich NULL in C. Das halte ich ganz genau so. Nichts desto trotz: Das Dillema besteht darin, dass NULL eben kein Schlüsselwort ist, sondern über diese unsägliche Makro-Definition eingebracht wird. In meinen Augen ist es in C++ noch schlimmer, da dort das Makro für NULL den Datentyp int haben muss und kein void * sein darf. Das sorgt bei überladenen Funktionen für Verwirrung. Hat aber natürlich seinen guten Grund (Templates). > Ist euch je ein Compiler untergekommen auf bei dem ihr nicht auf > Adresse 0 des executing environment zugreifen konntet? Auf manchen Environments werden zumindest Schreibzugriffe auf *0 protokolliert. Im DOS gabs früher oft Programme, die nach dem Beenden eine Meldung ala '0 Pointer write exception' ausgaben. Im VAX/VMS sind (waren?) sowohl Lese- als auch Schreibzugriffe in die erste Memory-Page illegal. Das wird vom VMS schon so gehandhabt: Die erste Page wird nicht gemappt und für die MMU werden alle Zugriffe darauf gesperrt. Der Grund ist tatsächlich der (laut damaligen DEC-Mitarbeitern), dass ungültige Pointerzugriffe oft mit kleinen Pointerwerten gemacht werden. Mit dieser einfachen Technik konnte man recht effektiv einen Grossteil von Zugriffsfehlern finden.
"Ist euch je ein Compiler untergekommen auf bei dem ihr nicht auf Adresse 0 des executing environment zugreifen konntet?" Ja. Ziemlich oft sogar. In OS/2 waren die ersten 64KB nicht gemappt, d.h. beim ersten Zugriff krachte der Prozess weg. Und in 16-bit 286 protected mode Betriebssystemen ging ein Zugriff auf 0:0 schon prinzipiell nicht.
Ok, vielleicht war die Frage ungenau formuliert, Die Bsp. die ihr bringt, zeigen meiner Ansicht nach dass der C-Compiler den Zugriff auf Adresse 0 sehr wohl in Zugriff auf Adresse 0 umgewandelt hat. (VAX,OS2) wenn der Zugriff auf diese Adresse aber erfolgt, dann kommt es zu einer Exception der Hardware und der Prozess fliegt raus. Nette Anzeige von Speicherzugriffsfehler für Leute die versuchen mit Nullpointer zuzugreifen. Die eigentliche Frage ist wenn ich einem Pointer 0 zuweise wird der C-Compiler einen Zugriff auf Adresse 0 kodieren oder nicht? Ist euch also schonmal ein C-Compiler untergekommen der in so einem Fall nicht einen Zugriff auf Adresse 0 kodiert?
Wie oben schon geschrieben, stand ich mal bei der Entwicklung von Compiler/Laufzeitsystem vor genau dieser Entscheidung. Eine Maschine, bei der Adresse 0 genau mitten drin im Adressraum lag. Ich hatte das Problem dann wohl gepflegt ignoriert und doch 0 benutzt, weil's bei der 32bit-Variante irrelevant war, effektiv nur die 16bit-Variante betraf. Und die wiederum betraf nur ein T212 Controller-System. Hat aber nicht viel gefehlt.
Ok dann bleibt es wohl bei der pragmatischen Methode, wenn ich einen Nullpointer will nehme ich NULL, alles andere ist unsauber. wenn ich auf Adresse 0 zugreifen will dann mache ich dass mit der Problematik im Hinterkopf, falls es also nicht funktioniert, eine Ebene tiefer im Assemblercode schauen ob der Zugriff auf Adresse 0 kodiert ist oder nicht.
> Aus welchem Standard zitierst du da; K&R,C89,C99? C99. Was anderes hab ich nicht. Aber das sollte bei C89 genauso aussehen. > nach dem Standard ist die Zuweisung mit integer constant "integer constant expression" > was wird denn das wenn es keine Konstannte ist, wie will der > Compiler den dafür sorgen das das zur Laufzeit noch auseinander > gehalten wird? Muß er nicht. Eine "integer constant expression" ist eine Compilezeit-Konstante. Daher kann er die als solche natürlich auch zur Compilezeit erkennen. > Ich ziehe einen sauberen Programmierstil vor und wenn ich einen > Nullpointer haben will, dann benutze ich NULL in C. Ich finde, daß NULL eigentlich nicht soviel besser ist als 0. In C++ finde ich es sogar schlechter. > Die nach 56) geforderte Konsistenz würde für mich bedeuten das ein > Zugriff auf Adresse 0 im executing environment auch möglich ist. Die ist nicht gefordert. Fußnoten sind nicht normativ. Außerdem steht dort "are intended to be consistent" und nicht "shall be consistent". Das ist nur ein Hinweis, wie es gedacht ist, keine Forderung. Im Haupttext steht ja auch explizit, daß das Mapping "implementation-defined" ist. > Da ich ihn über eine nicht konstante erzeugen kann muss der > Zugriff auf die selbe Adresse auch über eine konstante möglich > sein sonst wäre die Konsistenz verletzt. Wieso? Es heißt ja: Except as previously specified, ... Zuerst wird erklärt, daß eine "integer constant expression" mit dem Wert 0 eine "null pointer constant" ist. Danach kommt eine Erklärung für alle anderen Integers (alle Konstanten außer 0 und alle nicht-Konstanten). > Wahrscheinlich ist das eher eine Diskussion für das > C-Sprach-Standard Forum. Kannst ja mal im Usenet in comp.lang.c vorbeischauen. > Ist euch je ein Compiler untergekommen auf bei dem ihr nicht auf > Adresse 0 des executing environment zugreifen konntet? Ich muß ehrlich sagen, daß ich das nicht weiß. Ich mußte bisher noch nie auf diese Adresse zugereifen.
@Rolf Magnus Danke Rolf, durch dich habe ich endlich einen Weg gefunden wie man sauber auf Adresse 0 zugreifen kann ohne zu befürchten das der Compiler dazwischenpfuscht. siehe: http://c-faq.com/null/runtime0.html Ahnte ich doch schon das sich aus der integer constant expression eine Möglichkeit ergibt. http://c-faq.com/null/accessloc0.html Zeigt dann die möglichen Wege zum Zugriff. Mehr wollte ich eigentlich nicht. Bezüglich C++ scheint es ja auch einige Diskussionen zu diesem Thema zu geben http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1601.pdf
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.