Ich sehe hier zwei unterschiedliche Fragen.
Erstens, bei modernen Architekturen kann man ziemlich sicher davon ausgehen, dass Zeiger die gleiche Größe haben (es gibt also keine near/far-Zeiger; aber Zeiger auf Elementfunktionen sind keine regulären Zeiger und können eine andere Größe haben); und auf einem 32-Bit-System beträgt diese Größe in der Regel 32 Bit. C geht sogar so weit, void*
automatisch in etwas anderes umzuwandeln, denn letztendlich ist ein Zeiger nur eine Speicheradresse. Allerdings unterscheiden die Sprachdefinitionen verschiedene Zeiger als unterschiedliche Typen. Ich glaube, der Grund dafür ist, dass verschiedene Typen unterschiedliche Ausrichtungen haben können (die Regel für void*
besagt, dass nichts wirklich vom Typ void
sein kann, also wenn Sie einen Zeiger auf void
haben, kennen Sie wahrscheinlich den korrekten Typ und implizit die richtige Ausrichtung ( siehe Anmerkung))
Zweitens, wie andere bereits erwähnt haben, sind long
s und int
s grundlegend unterschiedliche Typen mit eingebauten Standardkonvertierungen. Die Standards verlangen, dass long
s mindestens so groß sind wie int
s, aber möglicherweise größer. Auf Ihrer Architektur ist die Ausrichtung wahrscheinlich dieselbe, aber auf anderen Architekturen könnte dies ebenfalls unterschiedlich sein.
In Ihrem Fall ist es möglich, eine Notlösung zu finden, aber das ist nicht portabel. Wenn Sie nicht die richtigen Funktionsdeklarationen #include
, und stattdessen einfach nur die Vorwärtsdeklaration selbst verwenden, sollten die Dinge magischerweise funktionieren, weil in Ihrem Fall long
s und int
s kompatibel sind (vorausgesetzt es gibt keine Vorzeichenprobleme; außerdem in C++ müssen Sie sowohl Ihre Deklarationen als auch die tatsächlichen Funktionsimplementierungen mit extern "C"
versehen, damit Sie keine Verknüpfungsfehler erhalten). Bis Sie auf einen anderen Compiler, ein anderes Betriebssystem, eine andere Architektur usw. wechseln.
Zum Beispiel könnten Sie in C++ folgendes tun:
// in Datei lib.cc
#include
extern "C" void foo_int(int* a)
{
std::cout << "foo_int " << *a << " unter der Adresse " << a <<'\n';
}
extern "C" void foo_long(long* a)
{
std::cout << "foo_long " << *a << " unter der Adresse " << a <<'\n';
}
// In Datei main.cc
extern "C" void foo_int(long* a);
extern "C" void foo_long(int* a);
int main()
{
int i = 5;
long l = 10;
foo_long(&i);
foo_int(&l);
}
(In C würden Sie extern "C"
entfernen und anstelle von cout
printf
verwenden).
Verwenden Sie GCC, um wie folgt zu kompilieren:
$ g++ -c lib.cc -o lib.o
$ g++ main.cc lib.o
$ ./a.out
foo_long 5 unter der Adresse 0x22cce4
foo_int 10 unter der Adresse 0x22cce0
ANMERKUNG Da es keine Objekte vom Typ void
gibt, kann ein void*
nur auf Objekte eines anderen Typs zeigen. Der Compiler kannte den tatsächlichen Typ, als er das Objekt dort platzierte. Der Compiler kannte auch die Ausrichtung für diesen Typ, als er das Objekt allozierte. Sie kennen die Ausrichtung möglicherweise nicht wirklich, aber die Umwandlung ist nur garantiert, wenn sie wieder auf den ursprünglichen Typ erfolgt, in diesem Fall werden Ausrichtung und Größe gleich bleiben.
Aber es gibt Komplikationen. Zum einen muss die Speicherung des Objekts an beiden Stellen gleich sein (kein Problem bei primitiven Typen). Zum anderen ist es möglich, mit void*
s auf beliebigen Speicher zu zeigen, aber Programmierer, die das tun, wissen wahrscheinlich, was sie tun.
0 Stimmen
Gute Frage und interessante Antworten. Wahrscheinlich ist die technisch sinnvolle Lösung, eines der Header-Datei-Typdefinitionen zu ändern - obwohl dies möglicherweise aus anderen Gründen schwierig ist, wie Sie sagten.