2010-01-12 5 views
12

Ich muss oft Code in anderen Sprachen schreiben, die mit C-Strukturen interagieren. In der Regel wird dazu Python-Code mit den Modulen struct oder ctypes geschrieben.Extrahiere die Felder einer C-Struktur

Also ich habe eine .h-Datei voller Struct-Definitionen, und ich muss manuell durch sie lesen und diese Definitionen in meinem Python-Code duplizieren. Dies ist zeitaufwändig und fehleranfällig, und es ist schwierig, die beiden Definitionen synchron zu halten, wenn sie sich häufig ändern.

Gibt es ein Tool oder eine Bibliothek in einer beliebigen Sprache (muss nicht C oder Python sein), die eine .h-Datei aufnehmen und eine strukturierte Liste ihrer Strukturen und ihrer Felder erstellen kann? Ich würde gerne in der Lage sein, ein Skript zu schreiben, um automatisch meine Strukturdefinitionen in Python zu generieren, und ich möchte dazu keinen beliebigen C-Code verarbeiten müssen. Reguläre Ausdrücke würden in 90% der Fälle gut funktionieren und dann für die restlichen 10% endlose Kopfschmerzen verursachen.

+3

"Reguläre Ausdrücke würden in 90% der Fälle gut funktionieren und dann für die restlichen 10% endlose Kopfschmerzen verursachen." Ist eine ziemlich gute Zusammenfassung von Regular Expressions. Außer ich würde die Verhältnisse um 50/50 machen. – captncraig

Antwort

10

Wenn Sie Ihren C-Code mit Debugging kompilieren (-g), kann pahole (git) Ihnen die genaue Struktur Layouts verwendet werden.

 
$ pahole /bin/dd 
… 
struct option { 
     const char *    name;     /*  0  8 */ 
     int      has_arg;    /*  8  4 */ 

     /* XXX 4 bytes hole, try to pack */ 

     int *      flag;     /* 16  8 */ 
     int      val;     /* 24  4 */ 

     /* size: 32, cachelines: 1, members: 4 */ 
     /* sum members: 24, holes: 1, sum holes: 4 */ 
     /* padding: 4 */ 
     /* last cacheline: 32 bytes */ 
}; 
… 

Dies sollte groß etwa 90% der Zeit und dann verursachen endlose Kopfschmerzen für die restlichen 10% sehr viel schöner zu analysieren als gerade C.

2

Haben Sie sich Swig angesehen?

0

Ein mein Freund für diese Aufgaben getan C-Parser, die er mit Kogge verwenden.

3

Werfen Sie einen Blick auf Swig oder SIP, die Schnittstellencode für Sie generieren oder ctypes verwenden würden.

5

Reguläre Ausdrücke sein funktionieren würde.

Die Kopfschmerzen passieren in den Fällen, in denen der C-Code eine Syntax enthält, an die Sie beim Schreiben Ihrer regulären Ausdrücke nicht gedacht haben. Dann gehst du zurück und erkennst, dass C nicht wirklich durch reguläre Ausdrücke analysiert werden kann, und das Leben macht keinen Spaß.

Probieren Sie es umzudrehen: definieren Sie Ihr eigenes einfaches Format, das weniger Trick erlaubt als C des Fall ist, und erzeugt sowohl die C-Header-Datei und den Python-Schnittstelle Code aus der Datei:

define socketopts 
    int16 port 
    int32 ipv4address 
    int32 flags 

Dann können Sie leicht einige Python schreiben, dies zu konvertieren: die struct verwendet

typedef struct { 
    short port; 
    int ipv4address; 
    int flags; 
} socketopts; 

und auch eine Python-Klasse zu emittieren drei Werte zu packen/entpacken (möglicherweise zwei von ihnen big-endian und der andere Native-endian, bis zu Ihnen) .

+0

Ich habe definitiv darüber nachgedacht, aber oft bekommen wir Code von einer anderen Firma, die wir brauchen, um ein benutzerdefiniertes Protokoll zu implementieren, und da wir ihren Code nicht umschreiben können, aber Zugriff auf ihre Header-Dateien haben, ist dieser Ansatz nicht nicht machbar. Wenn ich jedoch ein System mit C- und Python-Komponenten von Grund auf selbst implementieren würde, würde ich das definitiv tun. –

+0

Auch habe ich gerade gemerkt, dass mein Beispiel immer noch ziemlich schrecklich ist, da der Python-Code die plattformabhängige Auffüllung zwischen "port" und "ipv4address" berücksichtigen muss. Sie könnten vielleicht "fehleranfällig" mit diesem Schema umgehen, indem Sie die Header manuell in die DSL übersetzen und dann automatisch einige Tests (in C geschrieben) generieren, die sicherstellen, dass Ihre Struktur und die ursprüngliche Struktur identisch sind, indem Sie spezifische Werte schreiben zu den verschiedenen Feldern beider Strukturen und dann zu ihnen. Testen Sie dann den Python-Code auf die gleiche Weise. Wenn alle übereinstimmen, bist du gut. –

+1

... wenn deine Drittanbieter dir eine Header-Datei schicken, die du nicht in dein DSL übersetzen kannst, dann erweitere entweder das DSL oder beschwere dich ;-) Aber ich bevorzuge die Antwort von ephemient, es ist bestimmt viel weniger Arbeit, wenn nur weil alle Padding-Informationen direkt vom Compiler abgerufen werden. –

1

Ich habe ziemlich erfolgreich GCCXML bei ziemlich großen Projekten verwendet. Sie erhalten eine XML-Repräsentation des C-Codes (einschließlich Strukturen), die Sie mit etwas einfachem Python nachbearbeiten können.

1

ctypes-codegen oder ctypeslib (gleiche Sache, glaube ich) generiert ctypes Structure Definitionen (auch andere Dinge, glaube ich, aber ich habe nur versucht structs) unter Verwendung von GCCXML Header-Dateien parsen. Es wird nicht mehr unterstützt, wird aber wahrscheinlich in einigen Fällen funktionieren.

Verwandte Themen