2010-12-30 5 views
5

Ich habe Code, der eine Menge von komplizierten # define Fehlercodes hat, die nicht einfach zu decodieren sind, da sie über mehrere Ebenen verschachtelt sind.Wie kann ich eine Liste von #define-Werten aus C-Code generieren?

Gibt es eine elegante Möglichkeit, eine Liste von #defines mit ihren endgültigen numerischen Werten (oder was auch immer sie sonst sein können) zu bekommen?

Als Beispiel:

<header1.h> 
#define CREATE_ERROR_CODE(class, sc, code) ((class << 16) & (sc << 8) & code) 
#define EMI_MAX 16 

<header2.h> 
#define MI_1 EMI_MAX 

<header3.h> 
#define MODULE_ERROR_CLASS MI_1 
#define MODULE_ERROR_SUBCLASS 1 
#define ERROR_FOO CREATE_ERROR_CODE(MODULE_ERROR_CLASS, MODULE_ERROR_SUBCLASS, 1) 

Ich würde eine große Anzahl ähnlicher #defines haben ERROR passende _ [\ w _] +, die ich so aufzählen möchte, dass ich immer eine aktuelle Liste der Fehlercodes dass das Programm ausgeben kann. Ich brauche den numerischen Wert, weil das ganze Programm ausgedruckt wird (und nein, es ist keine Option, stattdessen eine Zeichenkette auszudrucken).

Vorschläge für gcc oder einen anderen Compiler wäre hilfreich.

+0

Haben Sie in Erwägung gezogen, ** echte Konstanten ** anstelle von #defines zu verwenden? –

+0

Das Ändern des Codes in "costs" wäre nicht praktikabel, da es von einer Quelle im Upstream-Bereich vererbt wird. – djs

Antwort

4

Ich denke, die Lösung ist eine Kombination aus @nmichaels und @ aschepler's Antworten.

Verwenden Sie die gcc-Option -dM, um eine Liste der Makros zu erhalten. Verwenden Sie Perl oder awk oder was auch immer, um 2 Dateien aus dieser Liste zu erstellen:

1) Macros.h, enthält nur die #defines.

2) Codes.c, die

#include "Macros.h" 

ERROR_FOO = "ERROR_FOO" 
ERROR_BAR = "ERROR_BAR" 

enthält (zB: extrahieren jede #define ERROR_x in eine Linie mit dem Makro und einem String

jetzt gcc -E Codes.c ausführen, sollte eine Datei mit allen erstellen.. die Makros erweitert. Die Ausgabe etwas wie

1 = "ERROR_FOO" 
2 = "ERROR_BAR" 

aussehen soll ich gcc praktisch nicht, hat so nicht getestet ...

+1

Ich habe es ausprobiert und mit nur 6 Perl pro Zeile habe ich endlich eine sortierte Liste mit Zahlenwerten erhalten! Ein Problem mit dieser Lösung ist gcc -E -P gibt mir eine riesige Datei mit allen vorverarbeiteten Headern. Ich entfernte -P und nahm nur die Zeilen nach "# 2 Codes.c 2". Fix dies und ich denke, Sie gewinnen das Kopfgeld ... – djs

+0

getan. -P sollte "die Erzeugung von Linienmarkern in der Ausgabe des Präprozessors verhindern", was nützlich erschien, um die Datei sauberer erscheinen zu lassen. Naja. – AShelly

+0

Das Schlüsselkonzept, das ich hier vermisste, war, dass ich den Header nicht einfach vorverarbeiten konnte. Ich brauchte eine C-Datei, die auf diese Konstanten Bezug nahm, um sie tatsächlich zu erweitern. Den anderen Teil, den ich verpasst habe, habe ich selbst herausgefunden: Ich komme nur so weit wie ein arithmetischer Ausdruck, den ich beurteilen muss. Technisch nehme ich an, dass ich es kompilieren muss, aber ich habe betrogen und es perl eval übergeben. – djs

7

GCC -dMpreprocessor option könnte Sie bekommen, was Sie wollen.

+0

Das scheint die richtige Idee zu sein, aber es erweitert meine Makros nicht. Ich habe versucht, 'gcc -E-Wp, -dD header3.h zu laufen und ich am Ende mit genau der gleichen # define wie oben definiert. – djs

+1

@djs: Ja, es ist nicht ganz so weit. '-dM' gibt eine Liste von Makros aus, die Sie in ein Skript eingeben können, um die Erweiterungen zu generieren. – nmichaels

+0

Das Endergebnis ist aber, ich habe eine Liste von funktionsähnlichen Makros, die der Präprozessor erweitern kann, aber die ich sicherlich nicht machen möchte. Also brauche ich eine Möglichkeit, sie zu erweitern ... – djs

1

Wenn Sie eine vollständige Liste des Makros haben Sie sehen möchten, und alle sind numerisch, können Sie ein kurzes Programm nur für diesen Zweck kompilieren und ausführen:

#include <header3.h> 
#include <stdio.h> 

#define SHOW(x) printf(#x " = %lld\n", (long long int) x) 

int main(void) { 
    SHOW(ERROR_FOO); 
    /*...*/ 
    return 0; 
} 

Wie @nmichaels erwähnt, gcc -d Flags können dazu beitragen, dass die Liste der Makros angezeigt wird.

2

Das Programm 'coan' sieht aus wie das Werkzeug, nach dem Sie suchen. Es hat den Unter Befehl 'defs', die wie beschrieben wird:

defs [OPTION ...] [Datei ...] [Verzeichnis ...]

Select #define und #undef Direktiven die Eingabedateien entsprechend den Optionen und melden sie entsprechend den Optionen auf der Standardausgabe.

Weitere Informationen zu den Optionen finden Sie unter der zitierten URL. Beziehen Sie den Code here.

+0

Interessante Anwendung. Ich war wirklich aufgeregt, bis ich entdeckte, dass es keine Erweiterung von funktionsähnlichen Makros unterstützt. Es gibt jedoch einen offensichtlichen Fehler, um das Problem zu beheben. Vielleicht wird es eines Tages die Antwort sein. – djs

1

Hier ist eine kleine kreative Lösung:

Schreiben Sie ein Programm alle Ihre Identifikatoren mit einem regulären Ausdruck (wie \#define :b+(?<NAME>[0-9_A-Za-z]+):b+(?<VALUE>[^(].+)$ in .NET) entsprechen, ist es dann nur mit dem Namen einer anderen C-Datei angepasst haben erstellen:

Dann vorverarbeiten Sie Ihre Datei mit der Option/C/P (für VC++), und Sie sollten alle diese mit den Werten ersetzt bekommen. Dann verwenden Sie einen anderen Regex, um Dinge herum zu tauschen, und setzen Sie die Kommentare vor den Werten in #define Format - jetzt haben Sie die Liste der #define ist!

(Sie können mit GCC etwas Ähnliches tun.)

0

Gibt es eine elegante Weise, die ich

Für verschiedene Ebenen der Eleganz einer Liste von #defines mit ihren endgültigen Zahlenwerte bekommen, irgendwie.

#!/bin/bash 

file="mount.c"; 
for macro in $(grep -Po '(?<=#define)\s+(\S+)' "$file"); do 
    echo -en "$macro: "; 
    echo -en '#include "'"$file"'"\n'"$macro\n" | \ 
    cpp -E -P -x c ${CPPFLAGS} - | tail -n1; 
done; 

nicht narrensicher (#define \ \n macro(x) ... würde nicht gefangen werden - aber kein Stil, den ich gesehen habe, tut dass).

Verwandte Themen