2010-12-30 2 views
5

У меня есть код, который содержит много сложных кодов ошибок #define, которые нелегко декодировать, так как они вложены через несколько уровней.Как я могу сгенерировать список значений #define из C-кода?

Есть ли какой-либо изящный способ, я могу получить список #defines с их окончательными численными значениями (или что бы еще они ни были)?

В качестве примера:

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

я имел бы большое количество подобного #defines соответствующего ОШИБКУ _ [\ ш _] +, что я хотел бы перечислить, так что у меня всегда есть текущий список кодов ошибок что программа может выводить. Мне нужно числовое значение, потому что это все, что программа распечатает (и нет, это не вариант для печати строки).

Предложения для gcc или любого другого компилятора были бы полезны.

+0

Вы считали ** использование реальных констант ** вместо #defines? –

+0

Изменение кода на consts было бы нецелесообразным, поскольку оно наследуется от источника восходящего потока. – djs

ответ

4

Я думаю, что решение представляет собой комбо @nmichaels и ответы @ aschepler.

Используйте опцию gcc -dM для получения списка макросов. Используйте perl или awk или что-то еще, чтобы создать 2 файла из этого списка:

1) Macros.h, содержащий только #defines.

2) Codes.c, который содержит

#include "Macros.h" 

ERROR_FOO = "ERROR_FOO" 
ERROR_BAR = "ERROR_BAR" 

(т.е. извлечь каждый #define ERROR_x в соответствии с макро и строки

теперь управляют gcc -E Codes.c Это должно создать файл со всеми.. макросы расширяются. Вывод должен выглядеть примерно так

1 = "ERROR_FOO" 
2 = "ERROR_BAR" 

Я не НКУ под рукой, поэтому не проверял это ...

+1

Я пробовал это и с помощью всего лишь 6 перлов одного лайнера обработки. Наконец, я получил отсортированный список числовых значений! Одна проблема с этим решением - gcc -E -P дает мне массивный файл со всеми предварительно обработанными заголовками. Я удалил -P и взял только строки после «# 2 Codes.c 2». Исправьте это, и я думаю, что вы выиграли щедрость ... – djs

+0

сделано. -P должен был «Запретить создание линейных маркеров в выходе из препроцессора», что казалось полезным для того, чтобы сделать файл более чистым. Ну что ж. – AShelly

+0

Ключевой концепцией, которую я пропустил здесь, было то, что я не мог просто предварительно обработать заголовок, мне нужно было запустить файл C, ссылающийся на эти константы, чтобы фактически расширить его. Другая часть, которую я пропустил, поняла сама: я могу только дойти до арифметического выражения, которое мне нужно оценить. Технически я полагаю, что мне нужно скомпилировать его, но я обманул и передал его perl eval. – djs

7

GCC -dMpreprocessor option может предоставить вам то, что вы хотите.

+0

Это похоже на правильную идею, но она не расширяет мои макросы. Я попытался запустить 'gcc -E -Wp, -dD header3.h, и в итоге получим то же самое #define, как определено выше. – djs

+1

@ djs: Да, это не совсем так. '-dM' выведет список макросов, которые вы можете использовать в скрипте для генерации расширений. – nmichaels

+0

Конечный результат, хотя у меня есть список макросов, подобных функциям, которые препроцессор может расширить, но который я, конечно, не хочу делать. Поэтому мне нужно каким-то образом расширить их ... – djs

1

Если у вас есть полный список макросов, которые вы хотите видеть, и все числовые, вы можете скомпилировать и запустить короткую программу только для этой цели:

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

Как уже упоминалось @nmichaels, ССЗ -d флаги могут помочь получить этот список макросов.

2

Программа 'coan' выглядит как инструмент, которым вы пользуетесь. Он имеет суб-команда 'Defs', которая описывается как:

DEFS [OPTION ...] [файл ...] [каталог ...]

Выберите #define и #undef директивы от входные файлы в соответствии с параметрами и сообщать о них на стандартном выходе в соответствии с параметрами.

См. Цитируемый URL для получения дополнительных сведений об этих параметрах. Получить код here.

+0

Интересное приложение. Я был очень взволнован этим, пока не обнаружил, что он не поддерживает расширение функциональных макросов. Есть дефект, открытый, чтобы исправить это, хотя, возможно, когда-нибудь это будет ответ. – djs

1

Вот немного творческое решение:

Напишите программу, чтобы соответствовать всем вашим идентификаторам с регулярным выражением (как \#define :b+(?<NAME>[0-9_A-Za-z]+):b+(?<VALUE>[^(].+)$ в .NET), то есть это создать другой файл C только с именами соответствующими:

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

Затем предварительно обработайте файл с помощью параметра/C/P (для VC++), и вы должны получить все замененные значениями. Затем используйте другое регулярное выражение, чтобы поменять местами, и поместите комментарии перед значениями в формате #define - теперь у вас есть список #define!

(Вы можете сделать что-то подобное с GCC.)

0

Есть ли элегантный способ я могу получить список #defines с их окончательных численных значений

Для различных уровней элегантности, вроде.

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

Не Foolproof (#define \ \n macro(x) ... не будет пойман, - но не стиль, который я видел, не делает , что).

Смежные вопросы