Wie kann ich einen C-Header einfügen, der ein C++-Schlüsselwort als Bezeichner in C++ verwendet?

Lesezeit: 6 Minuten

Benutzeravatar von CLearner
Klarer

Ich habe C++ verwendet und mit clang++ kompiliert. Ich möchte die einbeziehen Header für ein X11-Programm, das ich schreibe.

Leider verwendet dieser Header explicit für einige Feldnamen (z. B. Zeile 727) und das ist ein Schlüsselwort in C++.

Gibt es irgendwie, damit umzugehen?

xcb/xkb.h:

// ...

#ifdef __cplusplus
extern "C" {
#endif

// ...

typedef struct xcb_xkb_set_explicit_t {
    xcb_keycode_t keycode;
    uint8_t       explicit;
} xcb_xkb_set_explicit_t;

// ...

#ifdef __cplusplus
}
#endif

// ...

  • Melden Sie einen Fehler gegen xcb, um das Header-Erzeugungsskript zu aktualisieren. Siehe Quelle hier.

    – n. 1.8e9-wo-ist-meine-Aktie m.

    9. Mai um 20:15 Uhr


  • @πάνταῥεῖ — extern "C" bedeutet nicht „kompilieren Sie diesen Code, als ob es C wäre.

    – Peter Becker

    9. Mai um 20:18 Uhr

  • Das ist nicht das erste Mal passiert. Frühe Versionen der X-API hatten eine struct Mitglied genannt new. Es musste umbenannt werden, wodurch vorhandener Code gebrochen wurde. Aus diesem Grund hat C aufgehört, Schlüsselwörter hinzuzufügen, es sei denn, sie beginnen mit einem doppelten Unterstrich oder werden durch eine neue Header-Datei deklariert.

    – Davislor

    11. Mai um 0:39 Uhr


  • Keine Antwort posten, da dies eine Art Hack ist. Sie können den Header ändern und die Variable in umbenennen explicit_ oder so.

    – BЈовић

    11. Mai um 14:01 Uhr


  • @n.1.8e9-wo-ist-mein-sharem. Wenn das xcb-Projekt C++ nicht unterstützt, dann ist es kein Fehler, warum sollten sie sich um C++-Regeln kümmern, wenn sie nur C verwenden?

    – Hansenrik

    13. Mai um 4:24 Uhr

Benutzeravatar von HolyBlackCat
Heilige Schwarze Katze

Verwenden Sie ein Makro, um die Felder umzubenennen:

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wkeyword-macro"
#endif
#define explicit explicit_
#ifdef __clang__
#pragma clang diagnostic pop
#endif

#include <xcb/xkb.h>

#undef explicit

Die Verwendung eines Schlüsselworts als Makroname ist in Standard-C++ schlecht geformt, aber GCC, Clang (mit Pragma) und MSVC akzeptieren es. (Der Standard sagt, dass Sie es “nicht tun sollen”, siehe Referenz klärt dass es “missgebildet” bedeutet.)

  • Sowohl in C als auch in C++ sind Sprachschlüsselwörter nicht für die Neudefinition verfügbar. Es könnte mit einer Reihe von Compilern funktionieren, aber Compilern (oder ihren Präprozessoren) steht es frei, es abzulehnen. Und die Bedeutung von Pragmas ist per Definition implementierungsdefiniert.

    – Petrus

    10. Mai um 3:44 Uhr


  • @ Peter Mhm, das habe ich am Ende der Antwort erwähnt. Manchmal ist die vollständige Konformität nicht praktikabel.

    – HolyBlackCat

    10. Mai um 6:28 Uhr


  • Ich glaube nicht, dass es um “Konformität” geht. Etwas ablehnen zu dürfen bedeutet nicht immer, dass ein Compiler es ist erforderlich zu. (Manchmal ist dies der Fall, wie bei der Mehrdeutigkeit der Überladungsauflösung IIRC und in Fällen, in denen der ISO-Standard besagt, dass eine Diagnose erforderlich ist. Nur dann ist eine Implementierung nicht streng konform, wenn sie sich dafür entscheidet, sie trotzdem zu akzeptieren und etwas damit zu tun.) Wie auch immer, ich bin Ich bin mir nicht sicher, was @ Peters Punkt war, da Ihre Antwort diesen Vorbehalt bereits erwähnt. Wenn es nur Ihre Erinnerung bestätigt hat, dass es in ISO C++ illegal ist (oder zumindest nicht garantiert funktioniert), ist dies natürlich impl def’d

    – Peter Cordes

    10. Mai um 20:56 Uhr

  • @PeterCordes Mein Kommentar war, weil die Antwort den Kommentar mit “IIRC” qualifizierte und “illegal” nicht besonders genau angab. Das Neudefinieren von Sprachschlüsselwörtern mit dem Präprozessor führt zu undefiniertem Verhalten, da die Standards das resultierende Verhalten nicht wirklich einschränken (was im Allgemeinen eine ziemlich schwierige Sache wäre) – und dazu gehört auch, dass keine Diagnose erforderlich ist.

    – Petrus

    11. Mai um 1:40 Uhr

  • @Peter: Die erste Hälfte meines Kommentars richtete sich an HolyBlackCat als Antwort auf ihren Kommentar; Ich vermutete, dass sie dachten, der Standard schließe aus, dies zu akzeptieren. Aber wenn es vollständig UB ist, ist das gut: Compiler dürfen dann das Verhalten definieren, wenn sie es wünschen. (Nur der Teil am Ende war teilweise an Sie gerichtet; es funktioniert als Klarstellung, aber der Ton wirkte wie ein Einwand. Besonders der Teil, der darauf hinweist #pragma clang ... Die definierte Implementierung schien nutzlos umständlich.) Wie auch immer, danke für die eventuelle Klarstellung, dass ISO C++ das Verhalten undefiniert lässt.

    – Peter Cordes

    11. Mai um 1:47 Uhr


Benutzeravatar von eerorika
Erorika

Wie kann ich einen C-Header einfügen, der ein C++-Schlüsselwort als Bezeichner in C++ verwendet?

Es gibt keine standardkonforme Lösung, um einen solchen Header einbinden zu können. Um einen Header in C++ einbinden zu können, muss dieser in gültigem C++ geschrieben sein. Im Fall eines C-Headers müsste dieser daher in einer gemeinsamen Teilmenge von C und C++ geschrieben werden.

Die ideale Lösung besteht darin, den Header so zu fixieren, dass er gültiges C++ ist. Eine standardkonforme Problemumgehung besteht darin, einen C++-konformen Wrapper in C zu schreiben.

(Keine Antwort auf die genaue Frage, aber möglicherweise nützlich für das allgemeine Problem der Schnittstelle zwischen C und C++)

Wie wäre es, wenn Sie einen Zwischensatz von C-Dateien (.c & .h) verwenden, um den inkompatiblen Header zu umschließen und dem Rest Ihres Programms eine C++-kompatible Schnittstelle bereitzustellen? Wenn diese Schnittstelle High-Level genug ist, müssten Sie nur die inkompatible Header-Datei nur in die Wrapper-.c-Datei einschließen, sodass die Wrapper-.h-Header-Datei normal in den C++-Code eingefügt werden kann.

Abhängig von den Details können Sie am Ende ein paar triviale Daten kopieren, aber die resultierende C-Schnittstelle ist möglicherweise viel besser für Ihre spezifischen Anforderungen geeignet.

  • Wie würde das in der Praxis funktionieren? Da der Wrapper die Datei, die er zu umhüllen versucht, nicht einschließen kann.

    – Tschu

    11. Mai um 12:10 Uhr

  • @Chuu: Der Wrapper ist in C geschrieben, nicht in C++. So kann es zB eine Funktion namens aufrufen requires() (was ein Schlüsselwort in C++20 ist), solange dieser Name nicht über seine Header-Datei verfügbar gemacht wird. Es kann dann eine Funktion mit dem Namen verfügbar machen foo_requires() in seinem Header für die Verwendung in C++.

    – thkala

    11. Mai um 12:21 Uhr

Benutzeravatar von TLW
TLW

Eine Lösung besteht darin, Ihrem Makefile einen Generierungsschritt hinzuzufügen, der den Header kopiert und das Feld umbenennt, und stattdessen den automatisch generierten Header einzufügen.

(Dies ist im allgemeinen Fall zwischen schwierig und unmöglich, aber in diesem Fall, da der Header wahrscheinlich nicht verwendet wird explicit für alles andere auch nur ein einfaches (gnu) sed (s/\bexplicit\b/explicit_field/g oder so) würde funktionieren. Der schwierigere Teil besteht darin, die richtige zu kopierende Datei herauszufinden.)

Stellen Sie sicher, dass der Speicherort der kopierten Kopfzeile lautet Vor den ursprünglichen Header in Ihrem Include-Pfad, falls etwas anderes in Ihren Includes den Header indirekt enthält.

Das bloße Ändern eines Feldnamens sollte keine Auswirkungen auf zB ABI haben, zumindest für einen nominell C-kompatiblen Header. (In C++ gibt es Fälle, in denen das Umbenennen eines Felds Auswirkungen hat.)

1417060cookie-checkWie kann ich einen C-Header einfügen, der ein C++-Schlüsselwort als Bezeichner in C++ verwendet?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy