Есть ли правильный способ сделать макрос «печать сообщения и продолжить»? - PullRequest
2 голосов
/ 11 июля 2019

Я хочу иметь возможность сделать что-то вроде этого:

while (line = fgets(line, n, input)) {
    if (strlen(line) == 1)
        print_and_continue("Blank line.\n");
    printf("%s\n", line);
}

Обычно способ сделать это и охватить все синтаксические сложности - использовать причудливый цикл do while(0):

#define print_and_die(x) do {printf("%s\n", (x)); exit(1);} while (0)

Однако , я не могу использовать continue (или break в этом отношении) вместо exit(1), потому что это будет применяться к циклу do while(0), не петля, я хочу это.И конечно, я могу просто определить макрос следующим образом:

#define print_and_continue(x) {printf("%s\n", (x)); continue;}

И ожидать, что пользователь не будет писать код, подобный этому:

if (something)
   print_and_continue(x);
else {...}

Но я хочу знать, есть ли способчтобы охватить все синтаксические случаи?


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

if (condition) {
   printf("Failure.\n");
   continue;
}

Просто дляпроиллюстрируйте эту мысль: если есть много условий, из-за которых вы хотите пропустить обработку данных (или даже частично обработать данные перед их пропуском), тогда да, это очень полезно.

Сравните удобочитаемость двух.Последний является довольно повторяющимся и нечитаемым (и сложнее редактировать)

/* With print_and_continue() */
char buffer[BUFSIZ];
while (fgets(buffer, sizeof(buffer), input)) {
    if (strlen(buffer) < 10)
        print_and_continue("To small."); 
    if (strlen(buffer) > 100)
        print_and_continue("To large."); 
    if (strcmp(buffer, "Do not print this"))
        print_and_continue("Avoided printing a line.");
    fputs(buffer, output); 
}

/* Without print_and_continue() */
char buffer[BUFSIZ];
while (fgets(buffer, sizeof(buffer), input)) {
    if (strlen(buffer) < 10){
        printf("Too small.\n");
        continue; 
    }
    if (strlen(buffer) > 100) {
        printf("To large.\n");
        continue; 
    }
    if (strcmp(buffer, "Do not print this")) {
        printf("Avoided printing a line.\n");
        continue;
    }
    fputs(buffer, output); 
}

Ответы [ 2 ]

1 голос
/ 11 июля 2019

if(1){printf("%s\n", (x));continue;}else{} должно работать, но будет выдавать предупреждения о вложенном if-else на современных компиляторах (gcc / clang), если вы поставите такой макрос после if.

switch(1){case 1: printf("%s\n", (x))); continue;} должно быть более защищено от предупреждений.

Если вы хотите то же самое для break и без возможных вложенных предупреждений if, вам понадобится расширение выражения оператора: ({ printf("%s\n", (x)); continue; /*or break*/ }).

Если ваше реальное использование действительно так просто, как макрос print_and_continue, я бы посоветовал явный puts(X); continue; гораздо предпочтительнее макроса со скрытым изменением потока управления.

1 голос
/ 11 июля 2019

Вы не должны этого делать (как сказано в комментариях).Если вы все еще хотите это сделать (вы не должны), вы можете попробовать это так:

#include <stdio.h>

#define print_and_continue(x) if(printf("%s\n", (x))) continue; else do{} while(0)

int main(int argc, char* argv[]) {
    for(int i=0;i<argc;++i) {
        if(i%2==0)
            print_and_continue("Even arg");
        else
            printf("Uneven arg\n");
        printf("This is printed\n");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...