Forum: Mikrocontroller und Digitale Elektronik Zeigerübergabe


von Sebastian (Gast)


Lesenswert?

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

von Dietmar (Gast)


Lesenswert?

Speicherverletzung, klar!!!

Wo zeigt denn der Zeiger hin? Muß man dem nicht vorher eine Adresse
zuweisen?

Gruß

Dietmar

von Sebastian (Gast)


Lesenswert?

Adresse zuweisen, das sollte der Compiler erledigen.

PS: Call by Referenz nützt mir nichts, bzw. ist in meinem Fall sehr
unelegant.

von Bartholomäus S. (sam_vdp)


Lesenswert?

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

von A.K. (Gast)


Lesenswert?

"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.

von Egon (der wahre) (Gast)


Lesenswert?

Pff.
1
unsigned int* pADC;
2
pADC = malloc(sizeof(int));

ist viel einfacher.

von A.K. (Gast)


Lesenswert?

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.

von Karl heinz B. (kbucheg)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Wolfram (Gast)


Lesenswert?

>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

von Karl heinz B. (kbucheg)


Lesenswert?

> 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.

von Rolf Magnus (Gast)


Lesenswert?

>>"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.

von A.K. (Gast)


Lesenswert?

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.

von Sebastian (Gast)


Lesenswert?

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.

von Dirk D. (dirkd)


Lesenswert?

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?

von Karl heinz B. (kbucheg)


Lesenswert?

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

von Karl heinz B. (kbucheg)


Lesenswert?

> 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?

von Bartholomäus S. (sam_vdp)


Lesenswert?

>unsigned int ADC;
>SPI0_ADC( & ADC, 1 );

Was ich ja vor zwölf Posts auch schon geschrieben hab'...

von Wolfram (Gast)


Lesenswert?

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?

von A.K. (Gast)


Lesenswert?

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

von Karl heinz B. (kbucheg)


Lesenswert?

@Wolfram

Lies den C Standard.

von A.K. (Gast)


Lesenswert?

@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.

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Wolfram (Gast)


Lesenswert?

>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.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

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

von A.K. (Gast)


Lesenswert?

"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.

von A.K. (Gast)


Lesenswert?

"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.

von Uwe (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

>> 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 de&#64257;ned 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.

von Wolfram (Gast)


Lesenswert?

@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...

von A.K. (Gast)


Lesenswert?

"ich gehe dann erstmal ins Wochenende und bin am Montag sehr gespannt
auf diesen Thread..."

Spielverderber ;-).

von A.K. (Gast)


Lesenswert?

@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?

von Rolf Magnus (Gast)


Lesenswert?

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.

von Wolfram (Gast)


Lesenswert?

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?

von Karl heinz B. (kbucheg)


Lesenswert?

> 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.

von A.K. (Gast)


Lesenswert?

"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.

von Wolfram (Gast)


Lesenswert?

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?

von A.K. (Gast)


Lesenswert?

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.

von Wolfram (Gast)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Wolfram (Gast)


Lesenswert?

@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
Noch kein Account? Hier anmelden.