Lowlevel

Lowlevel => Softwareentwicklung => Thema gestartet von: MasterLee am 24. January 2012, 22:22

Titel: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: MasterLee am 24. January 2012, 22:22
Die Überschrift sollte eigentlich werden
„cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksichtigung der Segmentierung im 80386 Protected mode“

Man könnte würde man in seinen Betriebssystem extensiver nutzen Zeiger in der Form Selector+Offset verwenden. Der Nachteil wäre nun das sich die Konstruktion nicht mehr ohne weiteres casten ließe. Die Frage die sich mir nun stellt würden dadurch größere Probleme entstehen wenn die möglichkeit Zeiger in andere Typen zu casten entfallen würde?.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 24. January 2012, 23:44
Nichts, was sich nicht lösen ließe. Andere Programmiersprachen, die keine Zeiger haben, wie zum Beispiel Java, kommen ja auch ohne Casts gut zurecht. Ansonsten gibts es immer noch als Behelfsmöglichkeit unions und 64-Bit-Datentypen, sofern unterstützt. Du kannst dir ja mal Open Watcom anschauen. Der kann das, soweit ich weiß.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: Dimension am 25. January 2012, 06:55
Meinst du
struct {
    unsigned short seg;
    unsigned int off;
};
, oder
#define PACK_POINTER(seg, off) ((seg) & 0xFFFF | (off) << 16)(Keine Garantie gegen Overflows)

32-Bit-Zeiger bis 4gb sind doch immer auch 32-Bit-int, 64-Bit-Zeiger dagegen 64-Bit-int. Das Datensegment steht in DS :lol:.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: kevin am 25. January 2012, 09:21
32-Bit-Zeiger bis 4gb sind doch immer auch 32-Bit-int, 64-Bit-Zeiger dagegen 64-Bit-int. Das Datensegment steht in DS :lol:.
Das sind Near Pointer, die nur in das aktuelle Segment zeigen können. Wenn du einen Far Pointer willst, hat der im Protected Mode 48 Bit (16-Bit-Selektor plus 32-Bit-Offset) und im Long Mode vermutlich keinen Sinn. ;)
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 25. January 2012, 13:08
@Dimension: Wenn das auf mich bezogen war, dann meinte ich:

union pointer {
  void __far *ptr;
  struct raw {
    unsigned int offset;
    unsigned short segment;
  } raw;
};

void __far *maybe_make_farpointer(unsigned short seg, unsigned long off) {
  union pointer f;
  f.raw.offset = off;
  f.raw.segment = seg;
  return f.ptr;
}

bzw.
#define MAYBE_MAKE_FARPOINTER(segment, offset) ((void __far *)((offset) + (((unsigned long long)(segment)) << 32)))
Aber es kommt sicherlich in beiden Fällen auf den Compiler an, ob das tatsächlich funktioniert. (Das heißt der Code ist auch nur Freistil.) Ich habe die Frage so interpretiert, dass MasterLee darüber nachdenkt einen Compiler zu schreiben oder anzupassen. Im Fall von Open Watcom (und DOS-Compilern) ist das allerdings so, dass diese Casts auch direkt vom Compiler unterstützt werden, und die Makros MK_FP, FP_OFF und FP_SEG verwendet werden sollten, um zwischen den Darstellungen zu konvertieren.

Die Reihenfolge beim Ablegen von far-Pointern im Speicher sollte übrigens erst Offset (d.h. niederwertige Bytes), dann Segment sein. Das ist notwendig, wenn man auf Zeiger casten will, bzw. diese Werte direkt interpretieren will.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 25. January 2012, 13:21
Die Reihenfolge beim Ablegen von far-Pointern im Speicher sollte übrigens erst Offset (d.h. niederwertige Bytes), dann Segment sein. Das ist notwendig, wenn man auf Zeiger casten will, bzw. diese Werte direkt interpretieren will.
Gibt es einen guten Grund, das zu tun? Ich würde es für wichtiger halten, die Pointer so anzuordnen, wie der Prozessor es für einen m16:32-Operanden erwartet, und ich glaube, da kommt das Segment erst.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 25. January 2012, 15:06
Das Offset kommt zuerst. Im Intel Manual unter 4.3 Pointer Data Types gibt es ein Bild dazu. Keine Ahnung ob das ermöglichen soll Far-Pointer auch als Near-Pointer interpretieren zu können, oder ob es etwas damit zu tun hat, dass x86 Little-Endian ist. Aber eins von beiden nutze ich als Eselsbrücke.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: Dimension am 25. January 2012, 15:28
@Jidder: btw: priorityof("<<") < priorityof("+")
Sorry korigiert.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 25. January 2012, 16:07
Kannst du das genauer ausdrücken? Klammern kann man da nicht weglassen, falls du darauf hinauswillst.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 25. January 2012, 16:10
Ah, in Volume 1 steht das. Ich hätte fast nicht gedacht, dass das auch für was gut ist. ;)
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: Dimension am 25. January 2012, 16:56
hm? http://en.cppreference.com/w/cpp/language/operator_precedence

Edit: Moment... meine Referenz sagt mir zu den Gruppen 1..3 und 15..16 was anderes - Kein Anspruch auf Korrektheit.
OT: dafür dass mein Phone mir seit 2 stunden einen fehlenden Akku anzeigt, bin ich doch sehr real im Internet unterwegs.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 25. January 2012, 17:07
a+b<<c entspricht (a+b)<<c und nicht a+(b<<c), was dein Link ebenfalls besagt. Deswegen sind die Klammern notwendig.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: Dimension am 25. January 2012, 18:21
Ich glaube die Frage vom OP war eher, ob sein Compiler Standard-konform ist, wenn jeder Cast von bzw. zu far-pointern einen Error auslösen würde. Ob dies Sinn machen würde weiss ich nicht, aber 2 Werte in einem int wären schonmal nicht gegen Overflow geschützt.
void __far *ptr;
int num;
num = (int) ptr; // ERROR 1
ptr = (void __far *) num; // ERROR 2


Edit: Thema verfehlt, neuer Code.

Die letzten 3 Kommentare bitte ignorieren/ unter "irrelevant" abspeichern.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: bluecode am 26. January 2012, 20:38
@Dimension: Dein Code macht überhaupt keinen Sinn (void*-Pointer dereferenzieren?)

Standard-C garantiert beim casten afaik sowieso nur, dass in (u)intptr_t gecastet werden kann und wieder zurück (und das Ergebnis davon gleich dem Zeiger vorher ist). Ich würde vermuten, dass es nicht garantiert ist, dass man auf den Integer verändert und dann zurückcastet, bin mir aber in keinster Weise sicher. Problematischer ist, dass bei far-Zeigern, dass zwei Zeiger ungleich sein können aber trotzdem den gleichen Speicher adressieren. Unabhängig davon ist ständiges wechseln der Segmentregister eine bescheidene Idee.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: erik.vikinger am 27. January 2012, 20:20
Hallo,


Die Frage die sich mir nun stellt würden dadurch größere Probleme entstehen wenn die möglichkeit Zeiger in andere Typen zu casten entfallen würde?.
Ja, ich denke schon. Streng genommen ist jedes C-Programm das Pointer in beliebige Nicht-Pointer oder andersherum castet nicht so wirklich konform zum C-Standard. Es wird zwar zugesichert das man einen Pointer nach (u)intptr_t und wieder zurück casten kann und das Ergebnis beim == Vergleich mit dem Original true ergibt aber mehr auch nicht. Selbst die kleinste Rechenoperation darf den in (u)intptr_t gespeicherten Pointer irreparabel zerstören. Gerade das Rechnen mit FAR-Pointern ergibt ja auch keinen Sinn (wenn man mal vom x86-Real-Mode absieht in dem ja jeder FAR-Pointer auf eine eineindeutige lineare 20Bit-Adresse zurückzuführen ist, zuzüglich den Gate-A20-Spielchen natürlich) da unterschiedliche Selectoren ja bedeuten das die jeweiligen Offsets in völlig verschiedenen und unabhängigen Welten eine Bedeutung haben und Selectoren eigentlich keinen mathematischen Bezug zueinander haben.

Bei der Frage welcher Umfang an Rechenmöglichkeiten und Castingmöglichkeiten bei FAR-Pointern überhaupt einen Sinn ergibt bin ich zu dem Ergebnis gekommen das sämtliche Rechnenoperationen mit 2 Pointern grundsätzlich nicht erlaubt sein sollten und nur die einfachen Strichrechenoperationen zwischen einem Pointer und einem Integer (der die selbe Größe wie der Offset-Teil des Pointers haben muss und dann auch nur das Offset im Pointer beeinflusst) überhaupt erlaubt werden dürfen, jegliche Form von Selector-Arithmetik mach IMHO bei richtiger dynamischer Segmentierung keinen Sinn. Casts dürften dann auch nur mit (u)intptr_t erlaubt sein (und das sollte eine vom Compiler angebotene Struktur sein für die keinerlei Rechenoperatoren überladen sind). Das Problem was ich sehe ist das wenn ein Compiler das wirklich strickt durchsetzt das dann vermutlich doch einige C-Programme plötzlich nicht mehr compilierbar sind. Aber ohne es zu versuchen kann ich auch kaum abschätzen wie viele Programme das wirklich trifft, ich habe da die Hoffnung das dies vor allem Treiber und andere systemnahe Programme trifft deren Portierung eh von nur begrenztem Nutzen ist oder eben spezielle Librarys die man dann neu schreiben müsste aber nach Außen das selbe Interface behalten.


Grüße
Erik
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 28. January 2012, 10:47
Wenn du das machst, hast du kein C mehr.

C garantiert, dass uintptr_t ein Integertyp ist, also kann man damit rechnen. Und es erlaubt, zwei Pointer voneinander abzuziehen, wenn sie ins selbe Objekt zeigen.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: bluecode am 28. January 2012, 11:47
Ich würde mal vermuten man darf dann auch die Differenz der beiden Pointer wieder zum kleineren addieren und dieser muss dann mit dem größeren übereinstimmen, oder?
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 28. January 2012, 12:29
Ja, natürlich. Das ist Pointerarithmetik, alles ordentlich definiert. Du kannst auch eins mehr wieder dazuaddieren, ohne dass es undefiniert wird. Schwierig wird es erst, wenn du mit einem gecasteten Integer rumrechnest und dann wieder einen Pointer draus machst.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: erik.vikinger am 28. January 2012, 13:00
Hallo,


Wenn du das machst, hast du kein C mehr.
Deswegen vermute ich ja das dann einige Programme nicht mehr compilierbar sind. Die Frage die mich da noch interessiert ist: wie viele Programme trifft das wirklich? Wenn ich an meine eigenen C/C++-Programme denke (privat und beruflich) würde ich sagen das diese auch weiterhin noch compilierbar sind, einfach weil die IMHO solche Pointer-Tricks nicht benutzen (mir fallen auch nur wenige Fälle ein wo man sowas überhaupt benötigt und die liegen alle nicht im Bereich normaler C-Programme sondern eher sowas wie malloc/free oder die Speicherverwaltung in einem OS-Kernel).

C garantiert, dass uintptr_t ein Integertyp ist, also kann man damit rechnen.
Okay, aber welche Arten von Rechenoperationen sind denn damit sinnvoll? Mal ganz davon abgesehen das so ein Typ bei mir 48 oder 80 Bit groß wäre (was sich nur etwas umständlich auf die normalen Integer-Rechenbefehle der CPU abbilden lässt) so ergeben doch bei (u)intptr_t nur die selben sehr beschränkten Varianten einen Sinn wie bei Pointern direkt. Auch glaube ich nicht das es allzu viel real existierenden C-Code gibt in dem mit (u)intptr_t tatsächlich komplexe Rechenoperationen durchgeführt werden so das IMHO hier nur ein geringes Potential besteht ein vorhandenes Programm nicht mehr compilierbar werden zu lassen.

Und es erlaubt, zwei Pointer voneinander abzuziehen, wenn sie ins selbe Objekt zeigen.
Ist denn auch definiert was passieren soll wenn die zwei Pointer nicht ins selbe Objekt zeigen? Grundsätzlich gebe ich Dir ja Recht das es möglich sein sollte die Differenz zwischen 2 Pointern zu ermitteln (ebenso wie auch < , > , <= und >= Vergleiche zwischen 2 Pointern möglich sein sollten) aber bei einem segmentiertem Speichermodell ist das eben nicht immer möglich, nebst dessen dass das Ergebnis ein Integer mit der selben Größe wie der Offset-Teil sein muss und kein Pointer. Da ich mir es als recht schwierig vorstelle zur Laufzeit die entsprechenden Bedingungen zu prüfen und eine Verletzung auch korrekt zu behandeln bin ich daher dafür solche Operationen lieber gleich ganz zu verbieten. Ich denke auch nicht dass das eine nennenswerte Einschränkung darstellt, um z.B. die Offsets von Struktur-Membern zu ermitteln gibt es doch sicher auch andere Wege.


und dieser muss dann mit dem größeren übereinstimmen, oder?
Wimre sichert der C-Standard bei Pointer-Arithmetik gar nichts zu, das läuft alles unter "implementierungsspezifisch".


Du kannst auch eins mehr wieder dazuaddieren, ohne dass es undefiniert wird.
Ist dann auch definiert ob an dieser neuen Adresse auch tatsächlich Speicher vorhanden ist? Wimre nein.

Schwierig wird es erst, wenn du mit einem gecasteten Integer rumrechnest und dann wieder einen Pointer draus machst.
Solange man direkt bei Pointern bleibt hat der Compiler ja zumindest eine theoretische Chance das Gesamtconstruct zu verstehen und etwas sinnvolles daraus zu bauen. Das Problem an FAR-Pointern in simplen Integern ist eben das Selector-Arithmetik eigentlich keinen Sinn ergibt.


Grüße
Erik
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 28. January 2012, 13:16
C garantiert, dass uintptr_t ein Integertyp ist, also kann man damit rechnen.
Okay, aber welche Arten von Rechenoperationen sind denn damit sinnvoll?
Wiederholt durch 16 teilen und jeweils den Rest auf den Bildschirm ausgeben? ;)

Zitat
Und es erlaubt, zwei Pointer voneinander abzuziehen, wenn sie ins selbe Objekt zeigen.
Ist denn auch definiert was passieren soll wenn die zwei Pointer nicht ins selbe Objekt zeigen?
Nicht, dass ich wüsste (ich habe aber auch keine explizite Aussage gefunden, dass es undefiniert ist, der Standard scheint einfach nichts dazu zu sagen). Wenn du daraus also einen Segfault machen willst, ist das vermutlich erlaubt.

Zitat
Da ich mir es als recht schwierig vorstelle zur Laufzeit die entsprechenden Bedingungen zu prüfen und eine Verletzung auch korrekt zu behandeln bin ich daher dafür solche Operationen lieber gleich ganz zu verbieten. Ich denke auch nicht dass das eine nennenswerte Einschränkung darstellt, um z.B. die Offsets von Struktur-Membern zu ermitteln gibt es doch sicher auch andere Wege.
Was ist daran schwierig? Unterschiedliche Segmente -> Segfault. Gleiche Segmente -> Differenz der Offsets wird berechnet.

Abgesehen davon, dass ich keine andere Methode kenne, die Offsets zu berechnen (wobei ich mir nichtmal sicher bin, dass die normale definiert ist - an NULL liegt schließlich kein so ein Objekt), bedeutet jede Einschränkung, dass du das Ergebnis nicht mehr C nennen kann. Du musst dich also entscheiden, ob du C willst oder nicht. "Fast C" heißt "nicht C", das ist eine neue Sprache, für die du erstmal eine ordentliche Spec schreiben solltest.

Zitat
Wimre sichert der C-Standard bei Pointer-Arithmetik gar nichts zu, das läuft alles unter "implementierungsspezifisch".
Pointerarithmetik ist genau definiert, solange du innerhalb von einem Objekt (oder einem Element nach Arrayende) bleibst.

Zitat
Ist dann auch definiert ob an dieser neuen Adresse auch tatsächlich Speicher vorhanden ist? Wimre nein.
Wie groß dein Array war, musst du natürlich immer noch selber wissen. ;)

Aber wenn du ein char a[42] hast und p = &a[12], q = &a[14], dann ist genau definiert, dass  p + 2 * (q - p) = &a[16] ist, zum Beispiel.

Zitat
Solange man direkt bei Pointern bleibt hat der Compiler ja zumindest eine theoretische Chance das Gesamtconstruct zu verstehen und etwas sinnvolles daraus zu bauen. Das Problem an FAR-Pointern in simplen Integern ist eben das Selector-Arithmetik eigentlich keinen Sinn ergibt.
Ob der Typ ein Pointer oder ein Integer ist, spielt eigentlich nicht wirklich eine Rolle. Die interessante Beschränkung ist, dass man innerhalb eines Objekts bleiben muss. Zu char* konvertieren kannst du nämlich und darauf dann fröhlich rumrechnen und hinterher wieder in einen anderen Pointer zurückcasten. In der Praxis ist das genau dasselbe wie mit einem Integer herumzurechnen. Der theoretische Unterschied ist, dass es mit char* definiert und mit uintptr_t implementation defined.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: erik.vikinger am 28. January 2012, 19:04
Hallo,


Wiederholt durch 16 teilen und jeweils den Rest auf den Bildschirm ausgeben? ;)
Etwas das von printf mit %p erledigt wird und da die libc ja auch zur Plattform passen muss ist es IMHO kein Problem da drin auch mal einen kleinen Trick zu benutzen der nicht so ganz sauber ist (in meiner Heap-Implementierung baue ich auch Pointer recht frei zusammen und wieder auseinander, ich sehe da auch kein Problem darin das mein Code nicht portabel ist).

Nicht, dass ich wüsste (ich habe aber auch keine explizite Aussage gefunden, dass es undefiniert ist, der Standard scheint einfach nichts dazu zu sagen).
Also ich persönlich halte mich da lieber an die Devise: "alles was nicht ausdrücklich und explizit zugesichert wird ist auch nicht zugesichert, fertig".

Wenn du daraus also einen Segfault machen willst, ist das vermutlich erlaubt.
Ich denke auch dass das so erlaubt ist aber dafür würde ich immer zusätzlichen Code benötigen und das möchte ich auch wieder nicht, daher möchte ich das lieber gleich ganz verbieten um so den geringsten Aufwand zu haben.

Was ist daran schwierig? Unterschiedliche Segmente -> Segfault. Gleiche Segmente -> Differenz der Offsets wird berechnet.
Vielleicht mache ich mir das einfach auch nur zu schwierig. Eines meiner Probleme ist das wenn eine solche Differenz später wieder zu einem Pointer dazu addiert wird das es dann zu einem Überlauf kommen kann und der wird, falls er direkt im Speicherzugriffsbefehl passiert, von der CPU mit einer Exception beantwortet, es kann also passieren das die Funktionsfähigkeit des selben C-Codes vom Optimierungsgrad des Compilers abhängt und das sollte IMHO lieber vermieden werden.

Abgesehen davon, dass ich keine andere Methode kenne, die Offsets zu berechnen
offsetof() (http://www.cplusplus.com/reference/clibrary/cstddef/offsetof/), das ist IMHO auch deswegen nötig weil ja das tatsächliche Speicherlayout in Strukturen auch wieder implementierungsspezifisch ist. Das meistens dahinter im Endeffekt nur der selbe Hack steckt den Du auch direkt benutzen würdest ist da erst mal egal, immerhin muss dafür derjenige gerade stehen der die libc für die konkrete Plattform gebaut hat und der sollte genau wissen was geht und was nicht.

"Fast C" heißt "nicht C", das ist eine neue Sprache, für die du erstmal eine ordentliche Spec schreiben solltest.
Das ist mir schon klar, aber eine komplette Spec werde ich da trotzdem nicht schreiben sondern eher eine präzise Auflistung der Unterschiede. Auf der anderen Seite scheint der C-Standard genügend "Interpretationsspielraum" zu bieten das ich wohl trotzdem sagen kann das mein System 100% konform ist, aber da kommen wir dann in Bereiche die sonst eher bei der Interpretation von Bibel, Koran usw. benutzt werden.

Pointerarithmetik ist genau definiert, solange du innerhalb von einem Objekt (oder einem Element nach Arrayende) bleibst.
Sicher? Das würde ich arg bezweifeln aber ich lese (morgen) am besten noch mal genau nach. Ich kann mich jedenfalls nicht erinnern das im C-Standard sowas wie "( (&TYPE[i+2]) - (&TYPE[i+1]) ) == sizeof(TYPE)" als true zugesichert wird. Um wie viel ein Pointer bei (&TYPE)++ wirklich inkrementiert wird ist wimre auch implementierungsspezifisch und muss ebenfalls nicht zwangsläufig mit sizeof(TYPE) übereinstimmen.

Wie groß dein Array war, musst du natürlich immer noch selber wissen. ;)
Ja klar, aber was ist mit Padding und ähnlichen Dingen? Sowas darf der Compiler frei nach Befinden oder gewünschtem Optimierungsgrad entscheiden. Arrays sind nicht zwangsläufig kompakt, wimre noch nicht einmal char-Arrays.

Aber wenn du ein char a[42] hast und p = &a[12], q = &a[14], dann ist genau definiert, dass  p + 2 * (q - p) = &a[16] ist, zum Beispiel.
Hm, okay, trotzdem würde ich das nicht als guten C-Code bezeichnen, in einem Array sollte man IMHO nur mit dem Index zugreifen und nicht mit Pointer-Arithmetik.

In der Praxis ist das genau dasselbe wie mit einem Integer herumzurechnen. Der theoretische Unterschied ist, dass es mit char* definiert und mit uintptr_t implementation defined.
Sicher? So wie ich den C-Standard verstanden habe wird kein exakter und eineindeutiger Zusammenhang zwischen Pointern für Objekte und deren numerische Darstellung als Integer zugesichert. Theoretisch könnte eine CPU ja auch Speicheradressen in Gray-Code darstellen (bei einem Pointer++ müsste der Compiler dann einen anderen Rechenbefehl benutzen als für Integer++) und echter Standard-konformer C-Code müsste trotzdem funktionieren. Das die Differenz von 2 Pointern als Integer den numerischen Wert 12 hat bedeutet nicht das die 2 Objekte (auf die die beiden Pointer zeigen) auch wirklich 12 Bytes von einander entfernt im Speicher liegen, dass das trotzdem auf allen heute existierenden CPUs zutrifft ist noch keine Zusicherung.


Grüße
Erik
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 28. January 2012, 20:23
Meinst du denn, dass existierende Programme überhaupt die Fähigkeiten deiner Architektur ausnutzen können? Ich glaube nämlich nicht, dass du was anderes machen kannst als je ein Segment für Code, Stack und Daten anzulegen. Die Programme haben ja keine Möglichkeit mitzuteilen, wie die Daten logisch zusammenhängen. Existierende Programme können also die Vorteile der Segmentierung vermutlich nicht nutzen. Macht es überhaupt Sinn diese Programme mit mehr als diesem "Legacy-Modus" á la x86 zu unterstützen?

Pointerarithmetik ist genau definiert, solange du innerhalb von einem Objekt (oder einem Element nach Arrayende) bleibst.
Sicher? Das würde ich arg bezweifeln aber ich lese (morgen) am besten noch mal genau nach. Ich kann mich jedenfalls nicht erinnern das im C-Standard sowas wie "( (&TYPE[i+2]) - (&TYPE[i+1]) ) == sizeof(TYPE)" als true zugesichert wird. Um wie viel ein Pointer bei (&TYPE)++ wirklich inkrementiert wird ist wimre auch implementierungsspezifisch und muss ebenfalls nicht zwangsläufig mit sizeof(TYPE) übereinstimmen.
6.5.6 Additive Operators 9.

Deine Notation ist etwas ungenau. Es gilt:
TYPE foo[123];
int i;
&foo[i + 2] - &foo[i + 1] = (i + 2) - (i + 1) = 1
(uintptr_t)&foo[i + 2] - (uintptr_t)&foo[i + 1] = sizeof(foo[0])


Ja klar, aber was ist mit Padding und ähnlichen Dingen? Sowas darf der Compiler frei nach Befinden oder gewünschtem Optimierungsgrad entscheiden. Arrays sind nicht zwangsläufig kompakt, wimre noch nicht einmal char-Arrays.
Ein Array ist kompakt. (6.2.5 Types 20) Wenn du ein struct foo { int x; char y; } hast, kann der Compiler das auf 8 Bytes vergrößern, d.h. sizeof(struct foo) = 8, also auch Elemente, die nicht in Arrays sind, können mehr Platz einnehmen als nötig.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: erik.vikinger am 29. January 2012, 12:39
Hallo,


Meinst du denn, dass existierende Programme überhaupt die Fähigkeiten deiner Architektur ausnutzen können?
Äh, ja, also schon oft. Ich denke das alle Programme zumindest von dem Gewinn an Sicherheit mehr oder weniger profitieren können. Ein absolut fehlerfreies Programm (in dem es gar keine Buffer-Overflows usw. gibt) profitiert natürlich nicht davon aber auf wie viele Programme trifft das denn zu? Vom Geschwindigkeitsvorteil durch das (meistens) abgeschaltete Paging profitieren natürlich auch alle Programme.

Ich glaube nämlich nicht, dass du was anderes machen kannst als je ein Segment für Code, Stack und Daten anzulegen.
Das ist aber schon mehr als im klassischen Flat-Memory gemacht wird, dort liegt absolut alles (sogar der OS-Kernel) in einem einzigen Adressraum. Bei mir ist z.B. der OS-Kernel aus dem User-Mode mit wirklich gar keinem Pointer erreichbar (es gibt keine 48/80 Bit-Kombination die den Kernel aus dem User-Mode adressieren kann). Auch muss ein Programm bei mir ja nicht auf 4 Segmente (Code, Const, Data und Stack) beschränkt bleiben, ich habe z.B. vor das der Heap sich über viele Segmente verteilt. Mein malloc() wird sicher nicht jedes mal ein neues Segment erstellen (das wäre totale Speicherverschwendung, schon weil so ein Segment immer ganze Pages belegt und auch etwas an Verwaltungsdaten kostet) aber ich will für jede benutzte Objekt-Größe ein neues Segment erstellen und dieses Segment wie ein Array aus Elementen dieser Größe verwalten (die Verwaltung als Array ist auch ziemlich effizient implementierbar so das malloc und free bei mir ordentlich schnell werden).

Die Programme haben ja keine Möglichkeit mitzuteilen, wie die Daten logisch zusammenhängen.
Der logische Zusammenhang von verschiedenen Objekten braucht IMHO auch keinen Einfluss darauf haben wie diese Objekte über die Segmente verteilt sind (es wird ja überall mit FAR-Pointern gearbeitet), das einzigste was ich aber in jedem Fall vermeiden will ist das einzelne Objekte/Arrays über mehrere Segmente verteilt werden müssen (so wie im x86-RM bei Objekten/Arrays mit mehr als 64 kB) so das meine Segmente schon recht groß werden können.

Macht es überhaupt Sinn diese Programme mit mehr als diesem "Legacy-Modus" á la x86 zu unterstützen?
IMHO ja. Und selbst wenn es nur 5 Segmente sind (also der Heap nur ein einziges Segment benutzt) ist es ja schon deutlich besser als alles was Flat-Memory auch nur theoretisch anbieten kann. Dazu kommt das spätestens bei Multithreading noch mehr Vorteile zum tragen kommen: jeder Stack hat sein eigenes Segment und kann auch unabhängig von anderen Stacks wachsen so das man sich nicht schon vorher überlegen muss wie man eine potentiell unbekannte Anzahl von Stacks in den einen virtuellen Adressraum unterbringen will. Nebst dessen das für die Stacks auch immer virtueller Speicher verschwendet wird da ja nicht vorhersehbar ist welcher der Stacks eventuell etwas mehr wächst als andere. Bei Flat-Memory muss man die Größe der Stacks immer beschränken um eine vernünftige Koexistenz mehrerer Stack in einem virtuellen Adressraum sicherstellen zu können. Auch kann man bei Flat-Memory die Stack niemals 100% zuverlässig gegeneinander absichern wie ich da http://forum.lowlevel.eu/index.php?topic=2224.msg25456#msg25456 (http://forum.lowlevel.eu/index.php?topic=2224.msg25456#msg25456) schon mal dargelegt hatte. Von daher bin ich in jedem Fall der Meinung das auch alle existierenden Programme von Segmentierung einen Nutzen haben können.

6.5.6 Additive Operators 9.
Danke, lese ich mir nachher mal durch.

&foo[i + 2] - &foo[i + 1] = (i + 2) - (i + 1) = 1
Also hier fehlt irgendwo noch "sizeof(TYPE)" weil der Abstand der Indizes ja nur 1 beträgt aber der Abstand der Pointer der Objekt-Größe entsprechen sollte.

(uintptr_t)&foo[i + 2] - (uintptr_t)&foo[i + 1] = sizeof(foo[0])
Also das ist IMHO auf jeden Fall falsch. Solange Du die Differenz aus zwei Pointern bildest muss auch eine Integer-Zahl (vom Type ptrdiff_t) bei raus kommen die auch wieder als Offset zu gebrauchen sein muss aber wenn Du beide Pointer vorher nach uintptr_t umwandelst dann ist das IMHO nicht mehr gewährleistet. Was ist wenn eine CPU mal tatsächlich eine andere Binärdarstellung für Adressen als für normale (Integer-)Zahlen benutzt? Dann würde Dein Code nicht mehr funktionieren, der C-Standard schreibt auch explizit nicht vor das für Integer das Zweierkomplement zu benutzen ist so das es jedem frei steht hier was anderes zu nutzen.

Ein Array ist kompakt.
Im Hinblick auf sizeof(Type) (also inklusive Padding) ja, da hast Du recht. Auch muss das Padding immer gleich sein, egal ob das Objekt in einem Array ist oder alleine benutzt wird oder Teil einer (größeren) Struktur ist. Wenn das nicht gewährleistet wäre könnte man solche Objekte ja nicht kopieren da dann eventuell mal zu viele oder zu wenige Bytes kopiert werden würden. Sowas wie "( (&TYPE[i+2]) - (&TYPE[i+1]) ) == sizeof(TYPE)" wird also doch immer true ergeben müssen, ebenso wie das ein (&TYPE)++ auch immer um sizeof(Type) Bytes vorrücken muss, da hab ich wohl gestern nicht zu Ende gedacht.

Aber das hier der Vergleich am Ende true ergibt ist IMHO nicht zugesichert :*TYPE p1,p2;
p1 = &type;
p2 = (*TYPE)(((uintptr_t)p1) + sizeof(TYPE));  // eines der Probleme hier ist das die Größe von uintptr_t und size_t (der Return-Type von sizeof) nicht identisch sein muss so dass das Ergebnis schon deswegen ungültig sein könnte
p1++;
if (p1 == p2)  // hier kommt nur dann true raus wenn für Pointer und für Integer die selbe Binärdarstellung in der CPU benutzt wird und das sichert der C-Standard nicht zu
So wie ich den C-Standard verstehe ist es nicht zugesichert das Rechenoperationen die direkt mit Pointern durchgeführt werden und Rechenoperationen die mit Integer-Werten von Pointern durchgeführt werden das selbe Ergebnis erzeugen. C-Code der auf sowas basiert ist IMHO nicht 100% konform und wenn der auf meiner Plattform nicht mehr funktioniert dann ist das ein Fehler im C-Code und nicht im Compiler. Deswegen möchte ich diese Dinge ja am liebsten gleich vom Compiler ablehnen lassen damit ich nicht später irgendwelchen Merkwürdigkeiten nachstellen muss, nebst dessen das ich für händische Pointer-Arithmetik (vor allem mit Integern) auch absolut keine Notwendigkeit sehe (sowas kann man immer auch anders machen, von ein paar Spezialfällen innerhalb der Speicherverwaltung mal abgesehen).


Grüße
Erik
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: Dimension am 29. January 2012, 13:43
Mein malloc() wird sicher nicht jedes mal ein neues Segment erstellen (das wäre totale Speicherverschwendung, schon weil so ein Segment immer ganze Pages belegt und auch etwas an Verwaltungsdaten kostet) aber ich will für jede benutzte Objekt-Größe ein neues Segment erstellen und dieses Segment wie ein Array aus Elementen dieser Größe verwalten (die Verwaltung als Array ist auch ziemlich effizient implementierbar so das malloc und free bei mir ordentlich schnell werden).

Wenn du deinen Arrays od. Buffern dann noch einen Header mit 2 Feldern für Elementgröße und Anzahl der Elemente spendierst und diese Angaben für jeden Pointer hast, wirst du absolut keine Overflows mehr brauchen (siehe: fat pointer / http://en.m.wikipedia.org/wiki/Cyclone_(programming_language) (http://en.m.wikipedia.org/wiki/Cyclone_(programming_language))) Um diese dynamisch skalieren zu können ohne zu relokalisieren fallen mir, nur Vektortabellen ein.


Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 29. January 2012, 14:36
Mein malloc() wird sicher nicht jedes mal ein neues Segment erstellen (das wäre totale Speicherverschwendung, schon weil so ein Segment immer ganze Pages belegt und auch etwas an Verwaltungsdaten kostet) aber ich will für jede benutzte Objekt-Größe ein neues Segment erstellen und dieses Segment wie ein Array aus Elementen dieser Größe verwalten
Genau darauf wollte ich hinaus. malloc() hat ja keinen anderen Parameter als die Größe. Ich finde das macht das Argument, dass Buffer Overflows erkennbar sind, hinfällig. Buffer Overflows, die nur Objekte der gleichen Größe betreffen, können immer noch gleichwahrscheinlich auftreten, und haben die selben fatalen Folgen. Das mit den Stacks für die Threads ist zwar ganz nett, aber im Zeitalter von 64-Bit-Adressräumen haut mich das auch nicht mehr vom Hocker. Ich finde Segmentierung muss die strengen Garantien bezüglich der Limits auch an die Anwendungen weiterreichen können, sonst ist es nur Paging mit variabler Page-Größe und riesigem, statischem TLB (d.h. Deskriptortabelle) in der CPU. (Und die Anzahl der unentdeckten Buffer Overflows reduziert sich um ~1/n, wobei n die Anzahl der Objekte pro Segment ist.) Das heißt nicht, dass ich eine Lösung dafür habe, wie man existierenden Programme das beibringen kann, sondern ganz im Gegenteil glaube ich, dass der Versuch C-Programme nachträglich mit Garantien auszustatten, die nicht von C gewährt werden, zum Scheitern verurteilt ist.

Zu der Pointer-Sache: Ich glaube du vertauscht da etwas. Das erste Beispiel hat genau das Verhalten, das du im zweiten erwartest, und umgekehrt.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 30. January 2012, 10:39
Ich denke auch dass das so erlaubt ist aber dafür würde ich immer zusätzlichen Code benötigen und das möchte ich auch wieder nicht, daher möchte ich das lieber gleich ganz verbieten um so den geringsten Aufwand zu haben.
Den zusätzlichen Code brauchst du genau dann, wenn jemand Pointerarithmetik benutzt. Du kannst dir natürlich auch die Arbeit machen, jeden Code zu patchen, der das tut, weil er sonst nicht kompiliert. Halte ich aber insgesamt gesehen für ineffizienter als ein, zwei Instruktionen mehr zu generieren.

Zitat
Eines meiner Probleme ist das wenn eine solche Differenz später wieder zu einem Pointer dazu addiert wird das es dann zu einem Überlauf kommen kann und der wird, falls er direkt im Speicherzugriffsbefehl passiert, von der CPU mit einer Exception beantwortet, es kann also passieren das die Funktionsfähigkeit des selben C-Codes vom Optimierungsgrad des Compilers abhängt und das sollte IMHO lieber vermieden werden.
Wieso sollte es zu einem Überlauf kommen, solange man innerhalb eines Objekts bleibt? Und wenn man es nicht tut, ist das undefined behaviour und eine Exception ist absolut in Ordnung.

Zitat
offsetof() (http://www.cplusplus.com/reference/clibrary/cstddef/offsetof/), das ist IMHO auch deswegen nötig weil ja das tatsächliche Speicherlayout in Strukturen auch wieder implementierungsspezifisch ist. Das meistens dahinter im Endeffekt nur der selbe Hack steckt den Du auch direkt benutzen würdest ist da erst mal egal, immerhin muss dafür derjenige gerade stehen der die libc für die konkrete Plattform gebaut hat und der sollte genau wissen was geht und was nicht.
Und jetzt rate mal, wie offsetof implementiert ist? ;)

Das ist einfach ein Makro, das die Pointerarithmetik versteckt. Wenn das Makro also nicht mehr kompiliert, hast du auch kein offsetof. Als Funktion, die man dazulinken könnte, geht das nicht.

Zitat
Das ist mir schon klar, aber eine komplette Spec werde ich da trotzdem nicht schreiben sondern eher eine präzise Auflistung der Unterschiede. Auf der anderen Seite scheint der C-Standard genügend "Interpretationsspielraum" zu bieten das ich wohl trotzdem sagen kann das mein System 100% konform ist, aber da kommen wir dann in Bereiche die sonst eher bei der Interpretation von Bibel, Koran usw. benutzt werden.
Ohne weiter vom Thema abweichen zu wollen, vermute ich von dir, dass du dich weder mit Bibel noch Koran näher auseinandergesetzt hast und da womöglich Dinge missverstehst... (wobei ich vom Koran selber keine Ahnung habe)

Mein Vergleich wären eher juristische Spitzfindigkeiten über die Interpretation von Gesetzen - und man redet ja nicht umsonst von language lawyers.

Zitat
Sicher? Das würde ich arg bezweifeln aber ich lese (morgen) am besten noch mal genau nach. Ich kann mich jedenfalls nicht erinnern das im C-Standard sowas wie "( (&TYPE[i+2]) - (&TYPE[i+1]) ) == sizeof(TYPE)" als true zugesichert wird. Um wie viel ein Pointer bei (&TYPE)++ wirklich inkrementiert wird ist wimre auch implementierungsspezifisch und muss ebenfalls nicht zwangsläufig mit sizeof(TYPE) übereinstimmen.
Das ist falsch. Lies es nach, es ist alles wohldefiniert.

Zitat
Aber wenn du ein char a[42] hast und p = &a[12], q = &a[14], dann ist genau definiert, dass  p + 2 * (q - p) = &a[16] ist, zum Beispiel.
Hm, okay, trotzdem würde ich das nicht als guten C-Code bezeichnen, in einem Array sollte man IMHO nur mit dem Index zugreifen und nicht mit Pointer-Arithmetik.
Genau so ist die Pointerarithmetik definiert: Die Differenz zweier Pointer ist die Differenz der Indizes im Array. Und dass a nichts anderes als *(a + i) (und damit auch i[a]) ist, dürftest du ja selbst wissen.

Zitat
In der Praxis ist das genau dasselbe wie mit einem Integer herumzurechnen. Der theoretische Unterschied ist, dass es mit char* definiert und mit uintptr_t implementation defined.
Sicher? So wie ich den C-Standard verstanden habe wird kein exakter und eineindeutiger Zusammenhang zwischen Pointern für Objekte und deren numerische Darstellung als Integer zugesichert. Theoretisch könnte eine CPU ja auch Speicheradressen in Gray-Code darstellen (bei einem Pointer++ müsste der Compiler dann einen anderen Rechenbefehl benutzen als für Integer++) und echter Standard-konformer C-Code müsste trotzdem funktionieren. Das die Differenz von 2 Pointern als Integer den numerischen Wert 12 hat bedeutet nicht das die 2 Objekte (auf die die beiden Pointer zeigen) auch wirklich 12 Bytes von einander entfernt im Speicher liegen, dass das trotzdem auf allen heute existierenden CPUs zutrifft ist noch keine Zusicherung.
Ja. Jetzt hast du genau beschrieben, warum es implementation defined ist, wenn man auf einem uintptr_t rumrechnet. Wenn man es auf einem char* tut (und innerhalb eines Objekts bleibt, wie immer), dann ist es genau definiert und der Compile müsste auf deiner gray-codierten CPU mit dreiwertiger Logik und signed-Darstellung mit Basis -2 eben Zusatzaufwand treiben, um das gewünschte Ergebnis herzustellen.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: bluecode am 30. January 2012, 19:45
Zitat
offsetof() (http://www.cplusplus.com/reference/clibrary/cstddef/offsetof/), das ist IMHO auch deswegen nötig weil ja das tatsächliche Speicherlayout in Strukturen auch wieder implementierungsspezifisch ist. Das meistens dahinter im Endeffekt nur der selbe Hack steckt den Du auch direkt benutzen würdest ist da erst mal egal, immerhin muss dafür derjenige gerade stehen der die libc für die konkrete Plattform gebaut hat und der sollte genau wissen was geht und was nicht.
Und jetzt rate mal, wie offsetof implementiert ist? ;)
Das ist einfach ein Makro, das die Pointerarithmetik versteckt. Wenn das Makro also nicht mehr kompiliert, hast du auch kein offsetof. Als Funktion, die man dazulinken könnte, geht das nicht.
Da wäre ich mir nicht so sicher, gcc hat dafür ein builtin, siehe hier (http://gcc.gnu.org/onlinedocs/gcc/Offsetof.html). Aber keine Ahnung warum genau man das brauch, ich versteh auch nicht was es da so für Randfälle für den "member-designator" geben kann, die man eventuell mit Pointerarithmetik alleine nicht hinbekommt.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 30. January 2012, 21:57
Ah, nett. tyndur benutzt ein handgestricktes Makro. Könnte vielleicht deswegen sein, weil Pointerarithmetik wie gesagt nur innerhalb von Objekten klar definiert ist und man bei offsetof() keins hat, sondern auf (struct foo*) NULL zurückgreift. Andererseits weiß gcc ja auch, was er implementiert, insofern wäre da kein Builtin nötig. Irgendwie komisch.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: Dimension am 10. February 2012, 00:29
Aber das hier der Vergleich am Ende true ergibt ist IMHO nicht zugesichert :*TYPE p1,p2;
p1 = &type;
p2 = (*TYPE)(((uintptr_t)p1) + sizeof(TYPE));  // eines der Probleme hier ist das die Größe von uintptr_t und size_t (der Return-Type von sizeof) nicht identisch sein muss so dass das Ergebnis schon deswegen ungültig sein könnte
p1++;
if (p1 == p2)  // hier kommt nur dann true raus wenn für Pointer und für Integer die selbe Binärdarstellung in der CPU benutzt wird und das sichert der C-Standard nicht zu
So wie ich den C-Standard verstehe ist es nicht zugesichert das Rechenoperationen die direkt mit Pointern durchgeführt werden und Rechenoperationen die mit Integer-Werten von Pointern durchgeführt werden das selbe Ergebnis erzeugen. C-Code der auf sowas basiert ist IMHO nicht 100% konform und wenn der auf meiner Plattform nicht mehr funktioniert dann ist das ein Fehler im C-Code und nicht im Compiler. Deswegen möchte ich diese Dinge ja am liebsten gleich vom Compiler ablehnen lassen damit ich nicht später irgendwelchen Merkwürdigkeiten nachstellen muss, nebst dessen das ich für händische Pointer-Arithmetik (vor allem mit Integern) auch absolut keine Notwendigkeit sehe (sowas kann man immer auch anders machen, von ein paar Spezialfällen innerhalb der Speicherverwaltung mal abgesehen).
id main(){
char * p1 = 0;
short * p2 = 0;
printf("%p %p %p %p", p1, p2, p1 + 1, p2 + 1);
}
Ergibt bei mir:
(nil) (nil) 0x1 0x2
Habe keinen gcc zur Hand, da mein Android ungerootet ist, und nehme codepad.org: http://codepad.org/fIVT8TDA
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: bluecode am 10. February 2012, 22:19
Und was genau soll das zeigen, Dimension?  :?
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücks
Beitrag von: Dimension am 10. February 2012, 23:05
Korrigier mich wenn ich falsch liege, aber ging es nicht primär um Arithmetik mit Pointern und Integern? Ob GCC das spezifische Verhalten von GCC nun auf eine genaue Vorgabe in der Spezifikation hinweist, weiss ich nicht. Die Frage is doch wohl viel eher, ob GCC, Visual  Studio, Borland, Watcom, etc. Standardkonform compilieren.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: bluecode am 11. February 2012, 00:33
Nein, die Frage ist was genau standardkonform überhaupt bedeutet. Und da hilft ein Test mit Compiler X auf Platform Y halt garnichts.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: MasterLee am 16. February 2012, 10:05
Manche APIs definieren Felder die sowohl für direkte Werte als auch für Zeiger genutzt werden. Nehmen wir z.B. folgendes Beispiel:
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
...
case WM_MOVE:
int xPos = (int)(short) LOWORD(lParam);   // horizontal position
int yPos = (int)(short) HIWORD(lParam);   // vertical position
...
case WM_CREATE:
CREATESTRUCT *pCS=(CREATESTRUCT*)lParam;
...
Das würde auf jeden Fall ein Problem machen da hier abhängig davon was LPARAM überhaupt ist entweder ein cast von einem Zeiger auf Zahl und umgekehrt von Zahl auf Zeiger(irgendwie muss es auch reingekommen sein) durchgeführt wird.

Das würde nicht funktionieren wenn ein Zeiger komplexer definiert würde zum Beispiel als Produkt aus Selektor und Offset. Da aber die Firma die obiges verbrochen hat dafür bekannt hat nicht gerade Standard konform zu arbeiten wollte ich wissen ob es generell erlaubt ist ein Zeiger nach Integer oder umgekehrt zu casten.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: kevin am 16. February 2012, 10:08
Casts von Integer auf Pointer und umgekehrt sind im C-Standard wohldefiniert. Steht aber auch mehrfach in diesem Thread.
Titel: Re: cast von Zeiger auf nicht Zeiger und umgekehrt in C unter spezieller Berücksi...
Beitrag von: Jidder am 17. February 2012, 14:46
Das würde nicht funktionieren wenn ein Zeiger komplexer definiert würde zum Beispiel als Produkt aus Selektor und Offset. Da aber die Firma die obiges verbrochen hat dafür bekannt hat nicht gerade Standard konform zu arbeiten wollte ich wissen ob es generell erlaubt ist ein Zeiger nach Integer oder umgekehrt zu casten.

LPARAM ist ja long, und da hat unter 16-Bit-Windows ein Selektor-Offset-Paar reingepasst. Wenn du long als 64-Bit-Integer definierst, kannst du deinen 16:32-far-pointer da auch problemlos reinstecken. Wenn jetzt 64-Bit-far-pointer oder so nutzen willst, dann funktioniert der Code natürlich nicht mehr. Aber ich würde auch nicht unbedingt einen Port von Windows auf meinen Compiler/Architektur/was-auch-immer-du-im-Sinn-hast anstreben. Wenn du hingegen so eine API nur grob imitieren willst, dann kannst du einfach einen Parameter als Pointer statt als Integer vorsehen. Casts vom Offset-Teil des Pointers auf Integer sollten ja immer gehen.