2010-12-30 15 views
5

Mam kod, który ma wiele skomplikowanych kodów błędów #define, które nie są łatwe do odkodowania, ponieważ są zagnieżdżone na kilku poziomach.Jak wygenerować listę wartości #define z kodu C?

Czy istnieje jakiś elegancki sposób, w jaki mogę uzyskać listę #defines z ich ostatecznymi wartościami liczbowymi (lub cokolwiek innego mogą być)?

Jako przykład:

<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) 

chciałbym mieć dużą liczbę podobnych #defines pasującymi ERROR _ [\ w _] +, które chciałbym wyliczyć tak, aby zawsze mieć aktualną listę kodów błędów program może wyprowadzać. Potrzebuję wartości liczbowej, ponieważ to wszystko zostanie wydrukowane przez program (i nie, to nie jest opcja, aby wydrukować ciąg znaków).

Przydałyby się sugestie dotyczące gcc lub dowolnego innego kompilatora.

+0

Czy brałeś pod uwagę ** przy użyciu stałych stałych ** zamiast #defines? –

+0

Zmiana kodu na const nie byłaby praktyczna, ponieważ jest dziedziczona z poprzedniego źródła. – djs

Odpowiedz

4

Myślę, że rozwiązaniem jest kombinacja odpowiedzi @nmichaels i @ aschepler.

Użyj opcji gcc -dM, aby uzyskać listę makr. Użyj perl lub awk, lub cokolwiek, aby utworzyć 2 pliki z tej listy:

1) Makra.h, zawierające tylko # definicje.

2) Codes.c, który zawiera

#include "Macros.h" 

ERROR_FOO = "ERROR_FOO" 
ERROR_BAR = "ERROR_BAR" 

(tj wyodrębnić każdą #define ERROR_x w linii z makro i ciąg

teraz uruchomić gcc -E Codes.c To powinno utworzyć plik ze wszystkimi.. makra rozszerzony. wyjście powinno wyglądać

1 = "ERROR_FOO" 
2 = "ERROR_BAR" 

nie mam gcc poręczny, więc nie przetestowane ...

+1

Próbowałem tego i przy zaledwie 6 perlach na jednej linijce przetwarzania ostatecznie znalazłem posortowaną listę wartości numerycznych! Jednym z problemów z tym rozwiązaniem jest gcc -E -P, który daje mi masywny plik ze wszystkimi wstępnie przetworzonymi nagłówkami. Usunąłem -P i wziąłem tylko linie po "# 2 Codes.c 2". Napraw to i myślę, że wygrasz nagrodę ... – djs

+0

zrobione. -P miał "Inhibitować generowanie znaków linowych na wyjściu z preprocesora", co wydawało się przydatne dla uczynienia pliku czystszym. No cóż. – AShelly

+0

Kluczową koncepcją, za którą tęskniłem, było to, że nie mogłem po prostu wstępnie przetworzyć nagłówka, potrzebowałem uruchomić plik C odwołujący się do tych stałych, aby faktycznie go rozwinąć. Druga część, którą przegapiłem, sama się rozgryzłam: mogę tylko dojść do arytmetycznego wyrażenia, które muszę sprawdzić. Technicznie przypuszczam, że muszę go skompilować, ale oszukałem i przekazałem go perl eval. – djs

7

GCC -dMpreprocessor option może Ci pomóc, czego chcesz.

+0

To wydaje się być właściwym pomysłem, ale nie rozszerza moich makr. Próbowałem już uruchomić 'gcc -E -Wp, -dD nagłówek3.h i kończę z tym samym #define, jak zdefiniowano powyżej. – djs

+1

@djs: Tak, to nie do końca. '-dM' wyświetli listę makr, które można wprowadzić do skryptu, aby wygenerować rozszerzenia. – nmichaels

+0

W rezultacie mam listę makr funkcyjnych, które może rozwinąć preprocesor, ale na pewno nie chcę tego robić. Potrzebuję więc sposobu na ich rozszerzenie ... – djs

1

Jeśli masz pełną listę makr, które chcesz zobaczyć, a wszystkie są numeryczne, można skompilować i uruchomić krótki program właśnie do tego celu:

#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; 
} 

Jak @nmichaels wspomniano, GCC -d flagi mogą pomóc w wyświetleniu listy makr.

2

Program 'coan' wygląda jak narzędzie, które chcesz wykonać. Ma podmenu polecenie 'DEFS', która jest opisana jako:

DEFS [opcja ...] [...] [plik katalog ...]

Wybierz #define i #undef z dyrektyw pliki wejściowe zgodnie z opcjami i zgłoś je na standardowym wyjściu zgodnie z opcjami.

Zobacz cytowany adres URL, aby uzyskać więcej informacji o opcjach. Uzyskaj kod here.

+0

Interesująca aplikacja. Byłem bardzo podekscytowany, dopóki nie odkryłem, że nie obsługuje on rozszerzenia makr funkcyjnych. Jest jednak pewna wada, aby to naprawić, więc może pewnego dnia będzie to odpowiedź. – djs

1

Oto trochę twórcze rozwiązanie:

Napisz program, pasujące do wszystkich identyfikatorów z wyrażenia regularnego (jak \#define :b+(?<NAME>[0-9_A-Za-z]+):b+(?<VALUE>[^(].+)$ w .NET), następnie go utworzyć kolejny plik C z zaledwie nazwami dopasowanych:

void main() { 
    /*my_define_1*/ my_define_1; 
    /*my_define_2*/ my_define_2; 
    //... 
} 

Następnie należy przetworzyć plik za pomocą opcji/C/P (w przypadku VC++), a wszystkie wymienione wartości należy zastąpić wartościami. Następnie użyj innego wyrażenia regularnego, aby zamienić różne rzeczy i umieść komentarze przed wartościami w formacie #define - teraz masz listę #define!

(Można zrobić coś podobnego z GCC.)

0

Czy istnieje elegancki sposób mogę uzyskać listę #defines z ich ostatecznych wartości liczbowych

Na różnych poziomach elegancji, raczej.

#!/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; 

Nie niezawodnego (#define \ \n macro(x) ... nie zostanie złapany - ale nie styl Widziałem robi że).

Powiązane problemy