Удалить код между #if 0 и #endif при экспорте файла C в новый
Я хочу удалить все комментарии в toy.c
файл. Из Удалить комментарии из кода C/C++ я вижу, что я мог бы использовать
gcc -E -fpreprocessed -P -dD toy.c
Но некоторые из моего кода (скажем, устаревшие функции, которые я не хочу компилировать) заключены между #if 0
а также endif
как будто они были закомментированы.
- С одной стороны, приведенная выше команда не удаляет этот тип "комментария", потому что его удаление возможно только во время расширения макроса, которое
-fpreprocessed
предотвращает; - С другой стороны, у меня есть другие макросы, которые я не хочу расширять, поэтому удаление
-fpreprocessed
плохая идея
Я вижу здесь дилемму. Есть ли выход из этой ситуации? Благодарю.
Следующий пример игрушки "toy.c" достаточен для иллюстрации проблемы.
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
#if 0
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
gcc -E -fpreprocessed -P -dD toy.c
дает
#define foo 3
int main (void) {
return foo;
}
#if 0
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
в то время как gcc -E -P toy.c
дает
int main (void) {
return 3;
}
3 ответа
Спасибо за два других ответа.
Теперь я знаю о unifdef и sunifdef. Я счастлив узнать о существовании этих инструментов и о том, что я не единственный, кто хочет проводить такую очистку кода.
Я также написал "rm_if0_endif.c" (прилагается ниже) для удаления #if 0 ... #endif
блок, которого мне достаточно. Его философия основана на обработке текста. Сканирует входной скрипт C, находя #if 0
и правильное вложение endif
, так что этот блок может быть опущен при копировании с символа на символ.
Подход к обработке текста ограничен, так как он предназначен для #if 0 ... #endif
только случай, но это все, что мне нужно на данный момент. Программа A C - не единственный способ обработки текста такого рода. Ответ Жан-Франсуа Фабра демонстрирует, как это сделать на Python. Я также могу сделать что-то подобное в R, используя readLines
, startsWith
а также writeLines
, Я решил сделать это на C, поскольку я еще не эксперт в C, поэтому эта задача заставляет меня учиться. Вот демонстрация моего "rm_if0_endif.c". Обратите внимание, что программа может объединить несколько файлов C и добавить заголовок для каждого файла.
исходный входной файл "input.c"
#define foo 3 /* this is a macro */
// a toy function
int test1 (void) {
return foo;
}
#if 0
#undef foo
#define foo 4
#ifdef bar
#warning "??"
#endif
// this is deprecated
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
// another toy
int test2 (void) {
return foo;
}
Предварительная обработка gcc "gcc_output.c" (взята в качестве входных данных для моей программы)
gcc -E -fpreprocessed -P -dD input.c > gcc_output.c
#define foo 3
int test1 (void) {
return foo;
}
#if 0
#undef foo
#define foo 4
#ifdef bar
#warning "??"
#endif
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
int test2 (void) {
return foo;
}
окончательный вывод "final_output.c" из моей программы
"rm_if0_endif.c" имеет функцию полезности pattern_matching
и рабочая лошадка rm_if0_endif
:
void rm_if0_endif (char *InputFile,
char *OutputFile, char *WriteMode, char *OutputHeader);
Прикрепленный файл ниже имеет main
функция, делающая
rm_if0_endif("gcc_output.c",
"final_output.c", "w", "// this is a demo of 'rm_if0_endif.c'\n");
Это производит:
// this is a demo of 'rm_if0_endif.c'
#define foo 3
int test1 (void) {
return foo;
}
int test2 (void) {
return foo;
}
Приложение: "rm_if0_endif.c"
#include <stdio.h>
int pattern_matching (FILE *fp, const char *pattern, int length_pattern) {
int flag = 1;
int i, c;
for (i = 0; i < length_pattern; i++) {
c = fgetc(fp);
if (c != pattern[i]) {
flag = 0; break;
}
}
return flag;
}
void rm_if0_endif (char *InputFile,
char *OutputFile, char *WriteMode, char *OutputHeader) {
FILE *fp_r = fopen(InputFile, "r");
FILE *fp_w = fopen(OutputFile, WriteMode);
fpos_t pos;
if (fp_r == NULL) perror("error when opening input file!");
fputs(OutputHeader, fp_w);
int c, i, a1, a2;
int if_0_flag, if_flag, endif_flag, EOF_flag;
const char *if_0 = "if 0";
const char *endif = "endif";
EOF_flag = 0;
while (EOF_flag == 0) {
do {
c = fgetc(fp_r);
while ((c != '#') && (c != EOF)) {
fputc(c, fp_w);
c = fgetc(fp_r);
}
if (c == EOF) {
EOF_flag = 1; break;
}
fgetpos(fp_r, &pos);
if_0_flag = pattern_matching(fp_r, if_0, 4);
fsetpos(fp_r, &pos);
if (if_0_flag == 0) fputc('#', fp_w);
} while (if_0_flag == 0);
if (EOF_flag == 1) break;
a1 = 1; a2 = 0;
do {
c = fgetc(fp_r);
while (c != '#') c = fgetc(fp_r);
fgetpos(fp_r, &pos);
if_flag = pattern_matching(fp_r, if_0, 2);
fsetpos(fp_r, &pos);
if (if_flag == 1) a1++;
fgetpos(fp_r, &pos);
endif_flag = pattern_matching(fp_r, endif, 5);
fsetpos(fp_r, &pos);
if (endif_flag == 1) a2++;
} while (a1 != a2);
for (i = 0; i < 5; i++) c = fgetc(fp_r);
if (c == EOF) {
EOF_flag == 1;
}
}
fclose(fp_r);
fclose(fp_w);
}
int main (void) {
rm_if0_endif("gcc_output.c",
"final_output.c", "w", "// this is a demo of 'rm_if0_endif.c'\n");
return 0;
}
Там есть пара программ, sunifdef
("Сын unifdef
", которая доступна от unifdef) и coan
, который может быть использован, чтобы делать то, что вы хотите. Вопрос Есть ли препроцессор C, который устраняет блоки #ifdef на основе значений, определенных / неопределенных? есть ответы, которые обсуждают эти программы.
Например, учитывая "xyz37.c":
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
#if 0
int main (void) {
printf("%d\n", foo);
}
#endif
С помощью sunifdef
sunifdef -DDEFINED -ned < xyz37.c
дает
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
и с учетом этого файла "xyz23.c":
#if 0
This is deleted
#else
This is not deleted
#endif
#if 0
Deleted
#endif
#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif
#if 1
This is persistent
#else
This is inconsistent
#endif
Программа
sunifdef -DDEFINE -ned < xyz23.c
дает
This is not deleted
#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif
This is persistent
Это, я думаю, то, что вы после. -DDEFINED
варианты кажутся необходимыми; выберите любое имя, которое вы не используете в своем коде. Вы могли бы использовать -UNEVER_DEFINE_THIS
вместо этого, если вы предпочитаете. -ned
Опция оценивает постоянные условия и исключает соответствующий код. Без этого постоянные условия, такие как 0
а также 1
не устранены.
Я использовал sunifdef
счастливо в течение ряда лет (посягая на десятилетие). Я еще не нашел, что это сделало ошибку, и я использовал это, чтобы убрать некоторые отвратительно заумные наборы 'ifdeffery'. Программа coan
это развитие sunifdef
с еще большими возможностями.
Препроцессор не делает исключений. Вы не можете использовать это здесь, чтобы сделать это.
Простой конечный автомат, использующий python, может работать. Это даже обрабатывает вложенность (ну, может быть, не все случаи покрыты как вложенные #if 0
но вы можете сравнить источник до и после и вручную проверить). Также закомментированный код не поддерживается (но кажется, что он у вас есть)
вход (немного более сложный, чем ваш для демонстрации):
#define foo 3
int main (void) {
return foo;
}
#if 0
int main (void) {
#ifdef DDD
printf("%d\n", foo);
#endif
}
#endif
void other_function()
{}
Теперь код, используя регулярные выражения для обнаружения #if
& #endif
,
import re
rif0 = re.compile("\s*#if\s+0")
rif = re.compile("\s*#(if|ifn?def)")
endif = re.compile("\s*#endif")
if_nesting = 0
if0_nesting = 0
suppress = False
with open("input.c") as fin, open("output.c","w") as fout:
for l in fin:
if rif.match(l):
if_nesting += 1
if rif0.match(l):
suppress = True
if0_nesting = if_nesting
elif endif.match(l):
if if0_nesting == if_nesting:
suppress = False
if_nesting -= 1
continue # don't write the #endif
if not suppress:
fout.write(l))
выходной файл содержит:
#define foo 3
int main (void) {
return foo;
}
void other_function()
{}
так что вложение работало и #if 0
часть была успешно удалена. Не то, что sed "/#if 0/,/#endif/d
можно достичь.