2009-04-09 6 views
18

In einer Anwendung, die ich pflege, haben wir ein Problem mit Datei-Deskriptor-Einschränkungen festgestellt, die die stdlib betreffen. Dieses Problem betrifft nur die 32-Bit-Version der Standardbibliothek.#ifdef für 32-Bit-Plattform

Ich habe ein Update für meinen Code entwickelt und möchte es implementieren, aber nur beim Kompilieren für 32-Bit ausführbare Datei. Welches Preprozessor-Symbol kann ich #ifdef angeben, um festzustellen, ob der Code für ein 32- oder 64-Bit-Ziel kompiliert wird?

EDIT

Sorry, nicht erwähnt, ist der Code Cross-Plattform, Linux, Windows, Solaris und einige andere Unix-Varianten, vor allem für die Kompilierung mit GCC. Irgendwelche De-facto-Standards, die ich plattformübergreifend nutzen kann?

EDIT 2

ich einige Definitionen „__ILP23“ und „__LP64“ gefunden zu haben, wie sie scheinen arbeiten kann ... eine Diskussion here erklärt den Hintergrund auf der Unix-Plattform. Jeder hatte irgendwelche Erfahrungen mit diesen Definitionen? Wird das nutzbar sein?

+0

Das ist plattformabhängig. Verschiedene Betriebssysteme verwenden unterschiedliche # defines. Wenn du Glück hast, hat Boost irgendwo einen tragbaren Wrapper versteckt. Aber ansonsten müssen Sie nur nach den plattformspezifischen suchen. Auf welcher Plattform laufen Sie übrigens? – jalf

+0

Bearbeitet die Frage ... Code Ziele primär Windows, Solaris und Linux, mit Teilen auch unter AIX und HP-UX. – veefu

+0

Nur eine Idee: #if sizeof (int) == 64 – mmmmmmmm

Antwort

15

Ich bin mir nicht sicher, ob es eine universelle #if def ist, die angemessen ist. Der C++ - Standard definiert fast sicher keinen. Es gibt jedoch sicherlich plattformspezifische.

Zum Beispiel Windows-

#if _WIN64 
// 64 bit build 
#else 
// 32 bit build 
#endif 

EDIT OP erwähnte dies ein Cross-Compiler ist zwischen Windows und Nicht-Windows mit GCC und anderen Compilern

Es gibt keine universelle Makro, das verwendet werden kann für alle Plattformen und Compiler. Ein wenig Präprozessor-Magie kann jedoch den Trick leisten. Angenommen, Sie arbeiten nur an x86- und amd64-Chips, sollte der folgende Trick ausreichen. Es kann leicht für andere Plattformen erweitert werden, obwohl

#if _WIN64 || __amd64__ 
#define PORTABLE_64_BIT 
#else 
#define PORTABLE_32_BIT 
#endif 
+0

Ok, hört sich so an, kombiniert mit einigen gcc-Ermittlungen nach Chris 'Kommentaren mag den Trick machen. +1 euch beide. – veefu

4

Sie können einen gut bekannten Typ für seine Größe überprüfen, z. sizeof (int *) == 4 für eine 32-Bit-Plattform.

Wie sizeof bei compiletime bekannt ist glaube ich ein

if(sizeof(int*) == 4) 
{ 
    ... 
} 

der Trick

bearbeiten tun sollten: Die Kommentare sind richtig, Sie regelmäßig verwenden müssen, wenn, wird #if nicht funktionieren.

Wenn Sie C++ verwenden Sie könnten Vorlagencode erstellen und den Compiler die Spezialisierung für Sie basierend auf dem Aufruf von sizeof() auswählen lassen. Wenn Sie für eine 32-Bit-Plattform erstellen, würde der Compiler nur den Code für die 32-Bit-Plattform instanziieren. Wenn Sie für eine 654-Bit-Plattform erstellen, würde der Compiler nur den Code für die 64-Bit-Plattform instanziieren.

+0

Dies funktioniert jedoch nicht für einen #ifdef. sizeof ist Kompilierzeit, während #if Pre-Prozessor Zeit ist – JaredPar

+0

das ist ungültiger Code (getestet auf VS2008) – JaredPar

+0

Einverstanden. Getestet auf GCC 4.0.1 unter OS X Leopard. –

0

Ich glaube, die definieren, ist _WIN64

13

Ich empfehle bookmarking die predef SourceForge. Es gibt keine Antwort, aber es kann Ihnen sicherlich helfen, loszulegen.

EDIT: Für GCC-only-Code können Sie __i386__ verwenden, um für 32-Bit-x86-Chips zu überprüfen, und ich empfehle, versuchen __X86_64__ oder etwas Ähnliches für 64-Bit-x86-Chips zu überprüfen. (Anmerkung: Es ist mir aufgefallen, dass die vorherige Antwort mit __ia86__ eigentlich ein anderer Chip ist, kein 64-Bit-x86-Chip. Dies zeigt nur meine mangelnde Hardware-Erfahrung. Für diejenigen, die mehr über Hardware als ich, konsultieren die SourceForge Seite auf vordefinierten Makros, die ich oben verlinke. Es ist viel genauer als ich.) Es gibt einige andere, die funktionieren würden, aber diese beiden sollten ziemlich universell unter GCC-Versionen sein.

+0

Wird __ia64__ für eine normale intel64-Bit-Kompilierung wahr sein? Oder gibt es ein __amd64__ oder ähnliches? – JaredPar

+0

Ich habe keine Erfahrung mit 64-Bit-Architekturen (oder mit der Programmierung auf Nicht-Intel-Architekturen), aber nach der Predefs-Seite gibt es ein __amd64__ für 64-Bit-AMD. __ia64__ scheint x86-spezifisch zu sein. –

+0

__i386__ würde nur funktionieren, wenn für Intel-CPU kompilieren, richtig? Auf Solaris kompilieren wir für sparc-s2. – veefu

1

Je nach Betriebssystem und Compiler sind dies Implementierungsentscheidungen.

0

Es gibt kein solches Symbol, das vom C++ - Standard definiert wird - Ihre spezifische Plattform (die Sie in Ihrer Frage nicht angegeben haben) kann eine solche anbieten.

2

Was ich wahrscheinlich tun würde, ist in einem Makefile, festzustellen, ob Sie auf einer 32-Bit-Plattform oder 64-Bit-Verwendung von Uname sind. Fügen Sie dann CFLAGS, -DX32 oder -DX64 hinzu. Das könntest du einfach #ifdef X64.

Aber das ist nur eine Unix-Lösung. Ich bin mir nicht sicher, was ich unter Windows machen würde.

+0

Das Problem damit ist, obwohl das System für die Kompilierung verwendet wird, ist 64-Bit, möglicherweise kompiliert eine 32-Bit-ausführbare Datei. Sie haben jedoch recht, dass diese Information irgendwie im Makefile sichtbar gemacht werden muss. Dem Compiler muss mitgeteilt werden, ob 32 oder 64 anvisiert wird. Sollte in der Lage sein, das anzupassen. – veefu

2

Mindestens 32-Bit-Solaris eine Grenze von 256 Dateizeiger hat, weil die Struktur der Dateideskriptor in einem unsigned char Feld speichert. Dies wird aus Gründen der Abwärtskompatibilität mit einigen fast unmöglich alten Versionen von SunOS beibehalten. Andere Plattformen - ich bin versucht, die meisten anderen Plattformen zu sagen - teilen diese Beschränkung nicht. Auf der anderen Seite ist es für ein gewöhnliches Benutzerprogramm relativ ungewöhnlich, dass viele Dateien gleichzeitig geöffnet werden müssen; Es weist häufiger auf einen Fehler hin (nicht schließt die Dateien, wenn sie fertig sind) als nicht. Allerdings kann dies ein Problem für Datenbankserver sein, die gleichzeitig viele Datendateien geöffnet haben müssen.


Ein Kommentar sagt:

, dass fast es ist. Wir haben keine große Anzahl von Dateien geöffnet, aber der Server verarbeitet eine große Anzahl von Verbindungen von Clients. Socket-Handles und Dateideskriptoren scheinen von demselben Ort zu stammen. Wenn wir viele Verbindungen haben ‚fopen‘ schlägt fehl, da die System-Level-Aufruf zurückkehrt und fd> 255.

‚Sockel Griffe‘ Filedeskriptoren auf Systemaufrufebene sind, so kommen sie aus dem gleichen Ort als reguläre Dateideskriptoren für Dateien.

Wenn Sie dies umgehen müssen, müssen Sie Ihren aktuellen Socket-Öffnungscode umbrechen, sodass, wenn er einen Dateideskriptor im Bereich 0..255 erhält, 'dup2()' aufgerufen wird, um einen Dateideskriptor zu erstellen Der Bereich, den stdio nicht verwendet - und dann den ursprünglichen Dateideskriptor schließen. Der einzige Haken dabei ist, dass Sie im Auge behalten müssen, welche Dateideskriptoren verfügbar sind, denn dup2 schließt fröhlich den Zieldateideskriptor, wenn er gerade geöffnet ist.

Natürlich nehme ich an, dass Ihr Socket-Code Dateideskriptoren und keine Dateizeiger liest. Wenn das der Fall ist, haben Sie größere Probleme - zu viele Dinge wollen die gleichen Ressourcen nutzen und sie können nicht alle gleichzeitig nutzen.

+0

Das ist fast so. Wir haben keine große Anzahl von Dateien geöffnet, aber der Server verarbeitet eine große Anzahl von Verbindungen von Clients. Socket-Handles und Dateideskriptoren scheinen von demselben Ort zu stammen. Wenn wir viele Verbindungen haben, schlägt 'fopen' fehl, weil der Aufruf auf Systemebene zurückkehrt und fd> 255. – veefu

+0

+1 für aufschlussreiche, obwohl. – veefu

+0

Ja, das ist fast genau das, was ich implementiert habe. Eingeschlossene Aufrufe von 'socket' und 'accept' mit Code, der 'fcntl' aufruft, um das Handle zu duplizieren, wenn <255, das Original schließen und das höhere verwenden. Dies funktioniert gut, muss aber auf die benötigte Plattform isoliert werden. Daher Frage zu #ifdef. – veefu

1

Ich benutze eine Konstruktion wie diese für Windows:

 
#if defined(_WIN64) 
    //64-bit code 
#elif defined(_M_IX86) 
    //32-bit code 
#else 
#error "Unknown platform" 
#endif 

Versus:

 
#if defined(_WIN64) 
    // 64 bit code 
#else 
    // 32-bit code 
#endif 

In der erstgenannten Lösung, wegen der #error der Compiler in der Lage sein, Ihnen zu sagen, wo Sie brauchen Code für eine neue Plattform hinzufügen. Dies hilft Wartungsfreundlichkeit, sollte jemals eine Plattform gefunden werden, die weder 64-Bit noch 32-Bit ist. Ja, die _M_IX86 ist nicht genau gleichbedeutend mit 32-Bit, aber ich denke, die einzige 32-Bit-Plattform, die die meisten von uns unterstützen, ist tatsächlich x86. Also als praktische Maßnahme genügt es.

In der späteren Lösung müssen Sie manuell herausfinden, wo Sie Code für Ihre neue Plattform mit Grep oder etwas ähnliches benötigen. Dies ist mühsam und fehleranfällig.

Es fällt mir auf, dass die folgende Konstruktion auch akzeptabel wäre, obwohl ich es in der Produktion noch nicht getestet habe und auch nicht wirklich viel darüber nachgedacht habe.

 
#if defined(_WIN64) 
    //64-bit code 
#elif defined(_WIN32) 
    //32-bit code 
#else 
#error "Unknown platform" 
#endif 
Verwandte Themen